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 // ===========================================================================
9 // Support for zap compiler and zap files
10 // ===========================================================================
18 #include <corcompile.h>
20 #include "assemblyspec.hpp"
30 #include "virtualcallstub.h"
31 #include "typeparse.h"
32 #include "typestring.h"
33 #include "dllimport.h"
34 #include "comdelegate.h"
35 #include "stringarraylist.h"
37 #ifdef FEATURE_COMINTEROP
38 #include "clrtocomcall.h"
39 #include "comtoclrcall.h"
40 #include "winrttypenameconverter.h"
41 #endif // FEATURE_COMINTEROP
43 #include "dllimportcallback.h"
45 #include "sigbuilder.h"
47 #include "peimagelayout.inl"
50 #ifdef FEATURE_COMINTEROP
51 #include "clrprivbinderwinrt.h"
52 #include "winrthelpers.h"
55 #ifdef CROSSGEN_COMPILE
56 #include "crossgenroresolvenamespace.h"
63 #ifdef FEATURE_PERFMAP
67 #include "argdestination.h"
69 #include "versionresilienthashcode.h"
70 #include "inlinetracking.h"
72 #ifdef CROSSGEN_COMPILE
73 CompilationDomain * theDomain;
76 VerboseLevel g_CorCompileVerboseLevel = CORCOMPILE_NO_LOG;
79 // CEECompileInfo implements most of ICorCompileInfo
82 HRESULT CEECompileInfo::Startup( BOOL fForceDebug,
84 BOOL fForceInstrument)
86 SystemDomain::SetCompilationOverrides(fForceDebug,
92 m_fCachingOfInliningHintsEnabled = TRUE;
93 m_fGeneratingNgenPDB = FALSE;
95 _ASSERTE(!g_fEEStarted && !g_fEEInit && "You cannot run the EE inside an NGEN compilation process");
97 if (!g_fEEStarted && !g_fEEInit)
99 #ifdef CROSSGEN_COMPILE
100 GetSystemInfo(&g_SystemInfo);
102 theDomain = new CompilationDomain(fForceDebug,
107 // When NGEN'ing this call may execute EE code, e.g. the managed code to set up
109 hr = InitializeEE(COINITEE_DEFAULT);
113 // JIT interface expects to be called with
114 // preemptive GC enabled
118 Thread *pThread = GetThread();
122 GCX_PREEMP_NO_DTOR();
128 HRESULT CEECompileInfo::CreateDomain(ICorCompilationDomain **ppDomain,
129 IMetaDataAssemblyEmit *pEmitter,
131 BOOL fForceProfiling,
132 BOOL fForceInstrument,
133 BOOL fForceFulltrustDomain)
135 STANDARD_VM_CONTRACT;
137 COOPERATIVE_TRANSITION_BEGIN();
139 #ifndef CROSSGEN_COMPILE
140 AppDomainCreationHolder<CompilationDomain> pCompilationDomain;
142 pCompilationDomain.Assign(new CompilationDomain(fForceDebug,
146 CompilationDomain * pCompilationDomain = theDomain;
150 SystemDomain::LockHolder lh;
151 pCompilationDomain->Init();
155 pCompilationDomain->SetDependencyEmitter(pEmitter);
158 #ifdef DEBUGGING_SUPPORTED
159 // Notify the debugger here, before the thread transitions into the
160 // AD to finish the setup, and before any assemblies are loaded into it.
161 SystemDomain::PublishAppDomainAndInformDebugger(pCompilationDomain);
162 #endif // DEBUGGING_SUPPORTED
164 pCompilationDomain->LoadSystemAssemblies();
166 pCompilationDomain->SetupSharedStatics();
168 *ppDomain = static_cast<ICorCompilationDomain*>(pCompilationDomain);
173 ENTER_DOMAIN_PTR(pCompilationDomain,ADV_COMPILATION)
175 pCompilationDomain->InitializeDomainContext(TRUE, NULL, NULL);
177 pCompilationDomain->SetFriendlyName(W("Compilation Domain"));
178 SystemDomain::System()->LoadDomain(pCompilationDomain);
180 #ifndef CROSSGEN_COMPILE
181 pCompilationDomain.DoneCreating();
184 END_DOMAIN_TRANSITION;
187 COOPERATIVE_TRANSITION_END();
193 HRESULT CEECompileInfo::DestroyDomain(ICorCompilationDomain *pDomain)
195 STANDARD_VM_CONTRACT;
197 #ifndef CROSSGEN_COMPILE
198 COOPERATIVE_TRANSITION_BEGIN();
202 CompilationDomain *pCompilationDomain = (CompilationDomain *) pDomain;
204 // DDB 175659: Make sure that canCallNeedsRestore() returns FALSE during compilation
206 pCompilationDomain->setCannotCallNeedsRestore();
208 pCompilationDomain->Unload(TRUE);
210 COOPERATIVE_TRANSITION_END();
216 HRESULT MakeCrossDomainCallbackWorker(
217 CROSS_DOMAIN_CALLBACK pfnCallback,
220 STATIC_CONTRACT_MODE_COOPERATIVE;
221 STATIC_CONTRACT_SO_INTOLERANT;
223 HRESULT hrRetVal = E_UNEXPECTED;
224 BEGIN_SO_TOLERANT_CODE(GetThread());
225 hrRetVal = pfnCallback(pArgs);
226 END_SO_TOLERANT_CODE;
230 HRESULT CEECompileInfo::MakeCrossDomainCallback(
231 ICorCompilationDomain* pDomain,
232 CROSS_DOMAIN_CALLBACK pfnCallback,
235 STANDARD_VM_CONTRACT;
237 HRESULT hrRetVal = E_UNEXPECTED;
239 COOPERATIVE_TRANSITION_BEGIN();
242 // Switch to cooperative mode to switch appdomains
245 ENTER_DOMAIN_PTR((CompilationDomain*)pDomain,ADV_COMPILATION)
248 // Switch to preemptive mode on before calling back into
254 hrRetVal = MakeCrossDomainCallbackWorker(pfnCallback, pArgs);
256 END_DOMAIN_TRANSITION;
259 COOPERATIVE_TRANSITION_END();
264 #ifdef TRITON_STRESS_NEED_IMPL
265 int LogToSvcLogger(LPCWSTR format, ...)
267 STANDARD_VM_CONTRACT;
272 va_start(args, format);
273 s.VPrintf(format, args);
276 GetSvcLogger()->Printf(W("%s"), s.GetUnicode());
282 HRESULT CEECompileInfo::LoadAssemblyByPath(
285 // Normally this is FALSE, but crossgen /CreatePDB sets this to TRUE, so it can
286 // explicitly load an NI by path
287 BOOL fExplicitBindToNativeImage,
289 CORINFO_ASSEMBLY_HANDLE *pHandle)
291 STANDARD_VM_CONTRACT;
295 COOPERATIVE_TRANSITION_BEGIN();
297 Assembly * pAssembly;
298 HRESULT hrProcessLibraryBitnessMismatch = S_OK;
300 // We don't want to do a LoadFrom, since they do not work with ngen. Instead,
301 // read the metadata from the file and do a bind based on that.
305 // Pre-open the image so we can grab some metadata to help initialize the
306 // binder's AssemblySpec, which we'll use later to load the assembly for real.
308 PEImageHolder pImage;
313 pImage = PEImage::OpenImage(
316 // If we're explicitly binding to an NGEN image, we do not want the cache
317 // this PEImage for use later, as pointers that need fixup
318 // Normal caching is done when we open it "for real" further down when we
319 // call LoadDomainAssembly().
320 fExplicitBindToNativeImage ? MDInternalImport_NoCache : MDInternalImport_Default);
323 if (fExplicitBindToNativeImage && !pImage->HasReadyToRunHeader())
325 pImage->VerifyIsNIAssembly();
329 pImage->VerifyIsAssembly();
332 // Check to make sure the bitness of the assembly matches the bitness of the process
333 // we will be loading it into and store the result. If a COR_IMAGE_ERROR gets thrown
334 // by LoadAssembly then we can blame it on bitness mismatch. We do the check here
335 // and not in the CATCH to distinguish between the COR_IMAGE_ERROR that can be thrown by
336 // VerifyIsAssembly (not necessarily a bitness mismatch) and that from LoadAssembly
338 if (pImage->Has32BitNTHeaders())
340 hrProcessLibraryBitnessMismatch = PEFMT_E_32BIT;
343 if (!pImage->Has32BitNTHeaders())
345 hrProcessLibraryBitnessMismatch = PEFMT_E_64BIT;
350 spec.InitializeSpec(TokenFromRid(1, mdtAssembly), pImage->GetMDImport(), NULL, FALSE);
352 if (spec.IsMscorlib())
354 pAssembly = SystemDomain::System()->SystemAssembly();
358 AppDomain * pDomain = AppDomain::GetCurrentDomain();
360 PEAssemblyHolder pAssemblyHolder;
361 BOOL isWinRT = FALSE;
363 #ifdef FEATURE_COMINTEROP
364 isWinRT = spec.IsContentType_WindowsRuntime();
369 // It does not make sense to pass the file name to recieve fake type name for empty WinMDs, because we would use the name
370 // for binding in next call to BindAssemblySpec which would fail for fake WinRT type name
371 // We will throw/return the error instead and the caller will recognize it and react to it by not creating the ngen image -
372 // see code:Zapper::ComputeDependenciesInCurrentDomain
373 IfFailThrow(::GetFirstWinRTTypeDef(pImage->GetMDImport(), &szNameSpace, &szTypeName, NULL, NULL));
374 spec.SetWindowsRuntimeType(szNameSpace, szTypeName);
376 #endif //FEATURE_COMINTEROP
378 // If there is a host binder then use it to bind the assembly.
379 if (pDomain->HasLoadContextHostBinder() || isWinRT)
381 pAssemblyHolder = pDomain->BindAssemblySpec(&spec, TRUE, FALSE);
386 CoreBindResult bindResult;
387 spec.SetCodeBase(pImage->GetPath());
390 TRUE, // fThrowOnFileNotFound
393 // fNgenExplicitBind: Generally during NGEN compilation, this is
394 // TRUE, meaning "I am NGEN, and I am doing an explicit bind to the IL
395 // image, so don't infer the NI and try to open it, because I already
396 // have it open". But if we're executing crossgen /CreatePDB, this should
397 // be FALSE so that downstream code doesn't assume we're explicitly
398 // trying to bind to an IL image (we're actually explicitly trying to
400 !fExplicitBindToNativeImage,
402 // fExplicitBindToNativeImage: Most callers want this FALSE; but crossgen
403 // /CreatePDB explicitly specifies NI names to open, and cannot assume
404 // that IL assemblies will be available.
405 fExplicitBindToNativeImage
407 pAssemblyHolder = PEAssembly::Open(&bindResult,FALSE,FALSE);
410 // Now load assembly into domain.
411 DomainAssembly * pDomainAssembly = pDomain->LoadDomainAssembly(&spec, pAssemblyHolder, FILE_LOAD_BEGIN);
413 if (spec.CanUseWithBindingCache() && pDomainAssembly->CanUseWithBindingCache())
414 pDomain->AddAssemblyToCache(&spec, pDomainAssembly);
418 // Mark the assembly before it gets fully loaded and NGen image dependencies are verified. This is necessary
419 // to allow skipping compilation if there is NGen image already.
420 pDomainAssembly->GetFile()->SetSafeToHardBindTo();
423 pAssembly = pDomain->LoadAssembly(&spec, pAssemblyHolder, FILE_LOADED);
425 // Add a dependency to the current assembly. This is done to match the behavior
426 // of LoadAssemblyFusion, so that the same native image is generated whether we
427 // ngen install by file name or by assembly name.
428 pDomain->ToCompilationDomain()->AddDependency(&spec, pAssemblyHolder);
431 // Kind of a workaround - if we could have loaded this assembly via normal load,
433 *pHandle = CORINFO_ASSEMBLY_HANDLE(pAssembly);
435 EX_CATCH_HRESULT(hr);
437 if ( hrProcessLibraryBitnessMismatch != S_OK && ( hr == COR_E_BADIMAGEFORMAT || hr == HRESULT_FROM_WIN32(ERROR_BAD_EXE_FORMAT) ) )
439 hr = hrProcessLibraryBitnessMismatch;
442 COOPERATIVE_TRANSITION_END();
448 #ifdef FEATURE_COMINTEROP
449 HRESULT CEECompileInfo::LoadTypeRefWinRT(
450 IMDInternalImport *pAssemblyImport,
452 CORINFO_ASSEMBLY_HANDLE *pHandle)
454 STANDARD_VM_CONTRACT;
458 ReleaseHolder<IAssemblyName> pAssemblyName;
460 COOPERATIVE_TRANSITION_BEGIN();
466 mdToken tkResolutionScope;
467 if(FAILED(pAssemblyImport->GetResolutionScopeOfTypeRef(ref, &tkResolutionScope)))
469 else if(TypeFromToken(tkResolutionScope) == mdtAssemblyRef)
471 DWORD dwAssemblyRefFlags;
472 IfFailThrow(pAssemblyImport->GetAssemblyRefProps(tkResolutionScope, NULL, NULL,
474 NULL, NULL, &dwAssemblyRefFlags));
475 if (IsAfContentType_WindowsRuntime(dwAssemblyRefFlags))
479 pAssemblyImport->GetNameOfTypeRef(ref, &psznamespace, &pszname);
481 spec.InitializeSpec(tkResolutionScope, pAssemblyImport, NULL, FALSE);
482 spec.SetWindowsRuntimeType(psznamespace, pszname);
484 _ASSERTE(spec.HasBindableIdentity());
486 pAssembly = spec.LoadAssembly(FILE_LOADED);
489 // Return the module handle
492 *pHandle = CORINFO_ASSEMBLY_HANDLE(pAssembly);
504 EX_CATCH_HRESULT(hr);
506 COOPERATIVE_TRANSITION_END();
512 BOOL CEECompileInfo::IsInCurrentVersionBubble(CORINFO_MODULE_HANDLE hModule)
516 return ((Module*)hModule)->IsInCurrentVersionBubble();
519 HRESULT CEECompileInfo::LoadAssemblyModule(
520 CORINFO_ASSEMBLY_HANDLE assembly,
522 CORINFO_MODULE_HANDLE *pHandle)
524 STANDARD_VM_CONTRACT;
526 COOPERATIVE_TRANSITION_BEGIN();
528 Assembly *pAssembly = (Assembly*) assembly;
530 Module *pModule = pAssembly->GetManifestModule()->LoadModule(GetAppDomain(), file, TRUE)->GetModule();
533 // Return the module handle
536 *pHandle = CORINFO_MODULE_HANDLE(pModule);
538 COOPERATIVE_TRANSITION_END();
544 BOOL CEECompileInfo::CheckAssemblyZap(
545 CORINFO_ASSEMBLY_HANDLE assembly,
546 __out_ecount_opt(*cAssemblyManifestModulePath)
547 LPWSTR assemblyManifestModulePath,
548 LPDWORD cAssemblyManifestModulePath)
550 STANDARD_VM_CONTRACT;
554 COOPERATIVE_TRANSITION_BEGIN();
556 Assembly *pAssembly = (Assembly*) assembly;
558 if (pAssembly->GetManifestFile()->HasNativeImage())
560 PEImage *pImage = pAssembly->GetManifestFile()->GetPersistentNativeImage();
562 if (assemblyManifestModulePath != NULL)
564 DWORD length = pImage->GetPath().GetCount();
565 if (length > *cAssemblyManifestModulePath)
567 length = *cAssemblyManifestModulePath - 1;
568 wcsncpy_s(assemblyManifestModulePath, *cAssemblyManifestModulePath, pImage->GetPath(), length);
569 assemblyManifestModulePath[length] = 0;
572 wcscpy_s(assemblyManifestModulePath, *cAssemblyManifestModulePath, pImage->GetPath());
578 COOPERATIVE_TRANSITION_END();
583 HRESULT CEECompileInfo::SetCompilationTarget(CORINFO_ASSEMBLY_HANDLE assembly,
584 CORINFO_MODULE_HANDLE module)
586 STANDARD_VM_CONTRACT;
588 Assembly *pAssembly = (Assembly *) assembly;
589 Module *pModule = (Module *) module;
591 CompilationDomain *pDomain = (CompilationDomain *) GetAppDomain();
592 pDomain->SetTarget(pAssembly, pModule);
594 if (!pAssembly->IsSystem())
596 // It is possible to get through a compile without calling BindAssemblySpec on mscorlib. This
597 // is because refs to mscorlib are short circuited in a number of places. So, we will explicitly
598 // add it to our dependencies.
600 AssemblySpec mscorlib;
601 mscorlib.InitializeSpec(SystemDomain::SystemFile());
602 GetAppDomain()->BindAssemblySpec(&mscorlib,TRUE,FALSE);
604 if (!IsReadyToRunCompilation() && !SystemDomain::SystemFile()->HasNativeImage())
606 if (!CLRConfig::GetConfigValue(CLRConfig::INTERNAL_NgenAllowMscorlibSoftbind))
608 return NGEN_E_SYS_ASM_NI_MISSING;
617 CEECompileInfo::GetAssemblyMetaDataImport(CORINFO_ASSEMBLY_HANDLE assembly)
619 STANDARD_VM_CONTRACT;
621 IMDInternalImport * import;
623 COOPERATIVE_TRANSITION_BEGIN();
625 import = ((Assembly*)assembly)->GetManifestImport();
628 COOPERATIVE_TRANSITION_END();
634 CEECompileInfo::GetModuleMetaDataImport(CORINFO_MODULE_HANDLE scope)
636 STANDARD_VM_CONTRACT;
638 IMDInternalImport * import;
640 COOPERATIVE_TRANSITION_BEGIN();
642 import = ((Module*)scope)->GetMDImport();
645 COOPERATIVE_TRANSITION_END();
650 CORINFO_MODULE_HANDLE
651 CEECompileInfo::GetAssemblyModule(CORINFO_ASSEMBLY_HANDLE assembly)
653 STANDARD_VM_CONTRACT;
655 CANNOTTHROWCOMPLUSEXCEPTION();
657 return (CORINFO_MODULE_HANDLE) ((Assembly*)assembly)->GetManifestModule();
660 PEDecoder * CEECompileInfo::GetModuleDecoder(CORINFO_MODULE_HANDLE scope)
662 STANDARD_VM_CONTRACT;
666 COOPERATIVE_TRANSITION_BEGIN();
669 // Note that we go ahead and return the native image if we are using that.
670 // It contains everything we need to ngen. However, the caller must be
671 // aware and check for the native image case, since some fields will need to come
672 // from the CORCOMPILE_ZAP_HEADER rather than the PE headers.
675 PEFile *pFile = ((Module *) scope)->GetFile();
677 if (pFile->HasNativeImage())
678 result = pFile->GetLoadedNative();
680 result = pFile->GetLoadedIL();
682 COOPERATIVE_TRANSITION_END();
688 void CEECompileInfo::GetModuleFileName(CORINFO_MODULE_HANDLE scope,
691 STANDARD_VM_CONTRACT;
693 COOPERATIVE_TRANSITION_BEGIN();
695 result.Set(((Module*)scope)->GetPath());
697 COOPERATIVE_TRANSITION_END();
700 CORINFO_ASSEMBLY_HANDLE
701 CEECompileInfo::GetModuleAssembly(CORINFO_MODULE_HANDLE module)
703 STANDARD_VM_CONTRACT;
705 CANNOTTHROWCOMPLUSEXCEPTION();
707 return (CORINFO_ASSEMBLY_HANDLE) GetModule(module)->GetAssembly();
711 #ifdef CROSSGEN_COMPILE
713 // Small wrapper to avoid having too many crossgen ifdefs
715 class AssemblyForLoadHint
717 IMDInternalImport * m_pMDImport;
719 AssemblyForLoadHint(IMDInternalImport * pMDImport)
720 : m_pMDImport(pMDImport)
724 IMDInternalImport * GetManifestImport()
729 LPCSTR GetSimpleName()
732 IfFailThrow(m_pMDImport->GetAssemblyProps(TokenFromRid(1, mdtAssembly), NULL, NULL, NULL, &name, NULL, NULL));
736 void GetDisplayName(SString &result, DWORD flags = 0)
738 PEAssembly::GetFullyQualifiedAssemblyName(m_pMDImport, TokenFromRid(1, mdtAssembly), result, flags);
748 //-----------------------------------------------------------------------------
749 // For an assembly with a full name of "Foo, Version=2.0.0.0, Culture=neutral",
750 // we want any of these attributes specifications to match:
751 // DependencyAttribute("Foo", LoadHint.Always)
752 // DependencyAttribute("Foo,", LoadHint.Always)
753 // DependencyAttribute("Foo, Version=2.0.0.0, Culture=neutral", LoadHint.Always)
754 // The second case of "Foo," is needed only for intra-V2 compat as
755 // it was supported at one point during V2. We may be able to get rid of it.
756 template <typename ASSEMBLY>
757 BOOL IsAssemblySpecifiedInCA(ASSEMBLY * pAssembly, SString dependencyNameFromCA)
759 STANDARD_VM_CONTRACT;
761 // First, check for this:
762 // DependencyAttribute("Foo", LoadHint.Always)
763 StackSString simpleName(SString::Utf8, pAssembly->GetSimpleName());
764 if (simpleName.EqualsCaseInsensitive(dependencyNameFromCA, PEImage::GetFileSystemLocale()))
767 // Now, check for this:
768 // DependencyAttribute("Foo,", LoadHint.Always)
769 SString comma(W(","));
770 StackSString simpleNameWithComma(simpleName, comma);
771 if (simpleNameWithComma.EqualsCaseInsensitive(dependencyNameFromCA, PEImage::GetFileSystemLocale()))
775 // DependencyAttribute("Foo, Version=2.0.0.0, Culture=neutral", LoadHint.Always)
776 StackSString fullName;
777 pAssembly->GetDisplayName(fullName);
778 if (fullName.EqualsCaseInsensitive(dependencyNameFromCA))
784 template <typename ASSEMBLY>
785 void GetLoadHint(ASSEMBLY * pAssembly, ASSEMBLY *pAssemblyDependency,
786 LoadHintEnum *loadHint, LoadHintEnum *defaultLoadHint = NULL)
788 STANDARD_VM_CONTRACT;
790 *loadHint = LoadDefault;
792 if (g_pConfig->NgenHardBind() == EEConfig::NGEN_HARD_BIND_ALL)
793 *loadHint = LoadAlways;
795 const BYTE *pbAttr; // Custom attribute data as a BYTE*.
796 ULONG cbAttr; // Size of custom attribute data.
799 // Look for the binding custom attribute
801 IMDInternalImport *pImport = pAssembly->GetManifestImport();
803 IfFailThrow(pImport->GetAssemblyFromScope(&mdAssembly));
805 MDEnumHolder hEnum(pImport); // Enumerator for custom attributes
806 IfFailThrow(pImport->EnumCustomAttributeByNameInit(mdAssembly, DEPENDENCY_TYPE, &hEnum));
808 mdCustomAttribute tkAttribute; // A custom attribute on this assembly.
809 while (pImport->EnumNext(&hEnum, &tkAttribute))
811 // Get raw custom attribute.
812 IfFailThrow(pImport->GetCustomAttributeAsBlob(tkAttribute, (const void**)&pbAttr, &cbAttr));
814 CustomAttributeParser cap(pbAttr, cbAttr);
816 IfFailThrow(cap.ValidateProlog());
818 // Extract string from custom attribute
821 IfFailThrow(cap.GetNonNullString(&szString, &cbString));
823 // Convert the string to Unicode.
824 StackSString dependencyNameFromCA(SString::Utf8, szString, cbString);
826 if (IsAssemblySpecifiedInCA(pAssemblyDependency, dependencyNameFromCA))
828 // Get dependency setting
830 IfFailThrow(cap.GetU4(&u4));
831 *loadHint = (LoadHintEnum)u4;
837 // If not preference is specified, look for the built-in assembly preference
838 if (*loadHint == LoadDefault || defaultLoadHint != NULL)
840 IMDInternalImport *pImportDependency = pAssemblyDependency->GetManifestImport();
842 IfFailThrow(pImportDependency->GetAssemblyFromScope(&mdAssembly));
844 HRESULT hr = pImportDependency->GetCustomAttributeByName(mdAssembly,
845 DEFAULTDEPENDENCY_TYPE,
846 (const void**)&pbAttr, &cbAttr);
849 // Parse the attribute
852 CustomAttributeParser cap(pbAttr, cbAttr);
853 IfFailThrow(cap.ValidateProlog());
855 // Get default bind setting
857 IfFailThrow(cap.GetU4(&u4));
859 if (pAssemblyDependency->IsSystem() && CLRConfig::GetConfigValue(CLRConfig::INTERNAL_NgenAllowMscorlibSoftbind))
865 *defaultLoadHint = (LoadHintEnum) u4;
867 *loadHint = (LoadHintEnum) u4;
872 HRESULT CEECompileInfo::GetLoadHint(CORINFO_ASSEMBLY_HANDLE hAssembly,
873 CORINFO_ASSEMBLY_HANDLE hAssemblyDependency,
874 LoadHintEnum *loadHint,
875 LoadHintEnum *defaultLoadHint)
877 STANDARD_VM_CONTRACT;
883 Assembly *pAssembly = (Assembly *) hAssembly;
884 Assembly *pAssemblyDependency = (Assembly *) hAssemblyDependency;
886 ::GetLoadHint(pAssembly, pAssemblyDependency, loadHint, defaultLoadHint);
888 EX_CATCH_HRESULT(hr);
893 HRESULT CEECompileInfo::GetAssemblyVersionInfo(CORINFO_ASSEMBLY_HANDLE hAssembly,
894 CORCOMPILE_VERSION_INFO *pInfo)
896 STANDARD_VM_CONTRACT;
898 Assembly *pAssembly = (Assembly *) hAssembly;
900 pAssembly->GetDomainAssembly()->GetCurrentVersionInfo(pInfo);
905 void CEECompileInfo::GetAssemblyCodeBase(CORINFO_ASSEMBLY_HANDLE hAssembly, SString &result)
907 STANDARD_VM_CONTRACT;
909 COOPERATIVE_TRANSITION_BEGIN();
911 Assembly *pAssembly = (Assembly *)hAssembly;
912 _ASSERTE(pAssembly != NULL);
914 pAssembly->GetCodeBase(result);
916 COOPERATIVE_TRANSITION_END();
919 //=================================================================================
921 void FakePromote(PTR_PTR_Object ppObj, ScanContext *pSC, uint32_t dwFlags)
929 _ASSERTE(*ppObj == NULL);
930 *(CORCOMPILE_GCREFMAP_TOKENS *)ppObj = (dwFlags & GC_CALL_INTERIOR) ? GCREFMAP_INTERIOR : GCREFMAP_REF;
933 //=================================================================================
935 void FakePromoteCarefully(promote_func *fn, Object **ppObj, ScanContext *pSC, uint32_t dwFlags)
937 (*fn)(ppObj, pSC, dwFlags);
940 //=================================================================================
942 void FakeGcScanRoots(MetaSig& msig, ArgIterator& argit, MethodDesc * pMD, BYTE * pFrame)
944 STANDARD_VM_CONTRACT;
948 // Encode generic instantiation arg
949 if (argit.HasParamType())
951 // Note that intrinsic array methods have hidden instantiation arg too, but it is not reported to GC
952 if (pMD->RequiresInstMethodDescArg())
953 *(CORCOMPILE_GCREFMAP_TOKENS *)(pFrame + argit.GetParamTypeArgOffset()) = GCREFMAP_METHOD_PARAM;
955 if (pMD->RequiresInstMethodTableArg())
956 *(CORCOMPILE_GCREFMAP_TOKENS *)(pFrame + argit.GetParamTypeArgOffset()) = GCREFMAP_TYPE_PARAM;
959 // If the function has a this pointer, add it to the mask
962 BOOL interior = pMD->GetMethodTable()->IsValueType() && !pMD->IsUnboxingStub();
964 FakePromote((Object **)(pFrame + argit.GetThisOffset()), &sc, interior ? GC_CALL_INTERIOR : 0);
967 if (argit.IsVarArg())
969 *(CORCOMPILE_GCREFMAP_TOKENS *)(pFrame + argit.GetVASigCookieOffset()) = GCREFMAP_VASIG_COOKIE;
971 // We are done for varargs - the remaining arguments are reported via vasig cookie
975 // Also if the method has a return buffer, then it is the first argument, and could be an interior ref,
976 // so always promote it.
977 if (argit.HasRetBuffArg())
979 FakePromote((Object **)(pFrame + argit.GetRetBuffArgOffset()), &sc, GC_CALL_INTERIOR);
983 // Now iterate the arguments
986 // Cycle through the arguments, and call msig.GcScanRoots for each
988 while ((argOffset = argit.GetNextOffset()) != TransitionBlock::InvalidOffset)
990 ArgDestination argDest(pFrame, argOffset, argit.GetArgLocDescForStructInRegs());
991 msig.GcScanRoots(&argDest, &FakePromote, &sc, &FakePromoteCarefully);
995 void CEECompileInfo::GetCallRefMap(CORINFO_METHOD_HANDLE hMethod, GCRefMapBuilder * pBuilder)
998 DWORD dwInitialLength = pBuilder->GetBlobLength();
999 UINT nTokensWritten = 0;
1002 MethodDesc *pMD = (MethodDesc *)hMethod;
1005 ArgIterator argit(&msig);
1007 UINT nStackBytes = argit.SizeOfFrameArgumentArray();
1009 // Allocate a fake stack
1010 CQuickBytes qbFakeStack;
1011 qbFakeStack.AllocThrows(sizeof(TransitionBlock) + nStackBytes);
1012 memset(qbFakeStack.Ptr(), 0, qbFakeStack.Size());
1014 BYTE * pFrame = (BYTE *)qbFakeStack.Ptr();
1017 FakeGcScanRoots(msig, argit, pMD, pFrame);
1020 // Encode the ref map
1026 UINT cbStackPop = argit.CbStackPop();
1027 pBuilder->WriteStackPop(cbStackPop / sizeof(TADDR));
1029 nStackSlots = nStackBytes / sizeof(TADDR) + NUM_ARGUMENT_REGISTERS;
1031 nStackSlots = (sizeof(TransitionBlock) + nStackBytes - TransitionBlock::GetOffsetOfArgumentRegisters()) / sizeof(TADDR);
1034 for (UINT pos = 0; pos < nStackSlots; pos++)
1039 ofs = (pos < NUM_ARGUMENT_REGISTERS) ?
1040 (TransitionBlock::GetOffsetOfArgumentRegisters() + ARGUMENTREGISTERS_SIZE - (pos + 1) * sizeof(TADDR)) :
1041 (TransitionBlock::GetOffsetOfArgs() + (pos - NUM_ARGUMENT_REGISTERS) * sizeof(TADDR));
1043 ofs = TransitionBlock::GetOffsetOfArgumentRegisters() + pos * sizeof(TADDR);
1046 CORCOMPILE_GCREFMAP_TOKENS token = *(CORCOMPILE_GCREFMAP_TOKENS *)(pFrame + ofs);
1050 INDEBUG(nTokensWritten++;)
1051 pBuilder->WriteToken(pos, token);
1060 // Verify that decoder produces what got encoded
1063 DWORD dwFinalLength;
1064 PVOID pBlob = pBuilder->GetBlob(&dwFinalLength);
1066 UINT nTokensDecoded = 0;
1068 GCRefMapDecoder decoder((BYTE *)pBlob + dwInitialLength);
1071 _ASSERTE(decoder.ReadStackPop() * sizeof(TADDR) == cbStackPop);
1074 while (!decoder.AtEnd())
1076 int pos = decoder.CurrentPos();
1077 int token = decoder.ReadToken();
1082 ofs = (pos < NUM_ARGUMENT_REGISTERS) ?
1083 (TransitionBlock::GetOffsetOfArgumentRegisters() + ARGUMENTREGISTERS_SIZE - (pos + 1) * sizeof(TADDR)) :
1084 (TransitionBlock::GetOffsetOfArgs() + (pos - NUM_ARGUMENT_REGISTERS) * sizeof(TADDR));
1086 ofs = TransitionBlock::GetOffsetOfArgumentRegisters() + pos * sizeof(TADDR);
1091 _ASSERTE(*(CORCOMPILE_GCREFMAP_TOKENS *)(pFrame + ofs) == token);
1096 // Verify that all tokens got decoded.
1097 _ASSERTE(nTokensWritten == nTokensDecoded);
1101 void CEECompileInfo::CompressDebugInfo(
1102 IN ICorDebugInfo::OffsetMapping * pOffsetMapping,
1103 IN ULONG iOffsetMapping,
1104 IN ICorDebugInfo::NativeVarInfo * pNativeVarInfo,
1105 IN ULONG iNativeVarInfo,
1106 IN OUT SBuffer * pDebugInfoBuffer
1109 STANDARD_VM_CONTRACT;
1111 CompressDebugInfo::CompressBoundariesAndVars(pOffsetMapping, iOffsetMapping, pNativeVarInfo, iNativeVarInfo, pDebugInfoBuffer, NULL);
1114 HRESULT CEECompileInfo::GetBaseJitFlags(
1115 IN CORINFO_METHOD_HANDLE hMethod,
1116 OUT CORJIT_FLAGS *pFlags)
1118 STANDARD_VM_CONTRACT;
1120 MethodDesc *pMD = (MethodDesc *)hMethod;
1121 *pFlags = CEEInfo::GetBaseCompileFlags(pMD);
1126 //=================================================================================
1141 BOOL CEEPreloader::CanEmbedClassID(CORINFO_CLASS_HANDLE typeHandle)
1143 STANDARD_VM_CONTRACT;
1145 TypeHandle hnd = (TypeHandle) typeHandle;
1146 return m_image->CanEagerBindToTypeHandle(hnd) &&
1147 !hnd.AsMethodTable()->NeedsCrossModuleGenericsStaticsInfo();
1150 BOOL CEEPreloader::CanEmbedModuleID(CORINFO_MODULE_HANDLE moduleHandle)
1152 STANDARD_VM_CONTRACT;
1154 return m_image->CanEagerBindToModule((Module *)moduleHandle);
1157 BOOL CEEPreloader::CanEmbedModuleHandle(CORINFO_MODULE_HANDLE moduleHandle)
1159 STANDARD_VM_CONTRACT;
1161 return m_image->CanEagerBindToModule((Module *)moduleHandle);
1164 BOOL CEEPreloader::CanEmbedClassHandle(CORINFO_CLASS_HANDLE typeHandle)
1166 STANDARD_VM_CONTRACT;
1168 TypeHandle hnd = (TypeHandle) typeHandle;
1170 BOOL decision = m_image->CanEagerBindToTypeHandle(hnd);
1176 embedStats.noEmbed++;
1182 CorElementType arrType = hnd.AsArray()->GetInternalCorElementType();
1183 if (arrType == ELEMENT_TYPE_SZARRAY)
1184 embedStats.szarray++;
1186 CorElementType elemType = hnd.AsArray()->GetArrayElementTypeHandle().GetInternalCorElementType();
1187 if (elemType <= ELEMENT_TYPE_R8)
1188 embedStats.primitives++;
1195 /*static*/ BOOL CanEmbedMethodDescViaContext(MethodDesc * pMethod, MethodDesc * pContext)
1197 STANDARD_VM_CONTRACT;
1199 if (pContext != NULL)
1201 _ASSERTE(pContext->GetLoaderModule() == GetAppDomain()->ToCompilationDomain()->GetTargetModule());
1203 // a method can always embed its own handle
1204 if (pContext == pMethod)
1209 // Methods that are tightly bound to the same method table can
1210 // always refer each other directly. This check allows methods
1211 // within one speculative generic instantiations to call each
1214 if ((pContext->GetMethodTable() == pMethod->GetMethodTable()) &&
1215 pContext->IsTightlyBoundToMethodTable() &&
1216 pMethod->IsTightlyBoundToMethodTable())
1224 BOOL CEEPreloader::CanEmbedMethodHandle(CORINFO_METHOD_HANDLE methodHandle,
1225 CORINFO_METHOD_HANDLE contextHandle)
1227 STANDARD_VM_CONTRACT;
1229 MethodDesc * pContext = GetMethod(contextHandle);
1230 MethodDesc * pMethod = GetMethod(methodHandle);
1232 if (CanEmbedMethodDescViaContext(pMethod, pContext))
1235 return m_image->CanEagerBindToMethodDesc(pMethod);
1238 BOOL CEEPreloader::CanEmbedFieldHandle(CORINFO_FIELD_HANDLE fieldHandle)
1240 STANDARD_VM_CONTRACT;
1242 return m_image->CanEagerBindToFieldDesc((FieldDesc *) fieldHandle);
1246 void* CEECompileInfo::GetStubSize(void *pStubAddress, DWORD *pSizeToCopy)
1251 PRECONDITION(pStubAddress && pSizeToCopy);
1255 Stub *stub = Stub::RecoverStubAndSize((TADDR)pStubAddress, pSizeToCopy);
1256 _ASSERTE(*pSizeToCopy > sizeof(Stub));
1260 HRESULT CEECompileInfo::GetStubClone(void *pStub, BYTE *pBuffer, DWORD dwBufferSize)
1262 STANDARD_VM_CONTRACT;
1266 return E_INVALIDARG;
1269 return (reinterpret_cast<Stub *>(pStub)->CloneStub(pBuffer, dwBufferSize));
1272 HRESULT CEECompileInfo::GetTypeDef(CORINFO_CLASS_HANDLE classHandle,
1275 STANDARD_VM_CONTRACT;
1277 CANNOTTHROWCOMPLUSEXCEPTION();
1279 TypeHandle hClass(classHandle);
1281 *token = hClass.GetCl();
1286 HRESULT CEECompileInfo::GetMethodDef(CORINFO_METHOD_HANDLE methodHandle,
1289 STANDARD_VM_CONTRACT;
1291 CANNOTTHROWCOMPLUSEXCEPTION();
1293 *token = ((MethodDesc*)methodHandle)->GetMemberDef();
1298 /*********************************************************************/
1299 // Used to determine if a methodHandle can be embedded in an ngen image.
1300 // Depends on what things are persisted by CEEPreloader
1302 BOOL CEEPreloader::CanEmbedFunctionEntryPoint(
1303 CORINFO_METHOD_HANDLE methodHandle,
1304 CORINFO_METHOD_HANDLE contextHandle, /* = NULL */
1305 CORINFO_ACCESS_FLAGS accessFlags /*=CORINFO_ACCESS_ANY*/)
1307 STANDARD_VM_CONTRACT;
1309 MethodDesc * pMethod = GetMethod(methodHandle);
1310 MethodDesc * pContext = GetMethod(contextHandle);
1312 // IsRemotingInterceptedViaVirtualDispatch is a rather special case.
1314 // Other remoting intercepts are implemented by one of:
1315 // (1) in DoPrestub (for non-virtual calls)
1316 // (2) by transparent proxy vtables, where all the entries in the vtable
1317 // go to the same code.
1319 // However when calling virtual functions non-virtually the JIT interface
1320 // pointer to the code for the function in a stub
1321 // (see GetNonVirtualEntryPointForVirtualMethod).
1322 // Thus we cannot embed non-virtual calls to these functions because we
1323 // don't save these stubs. Unlike most other remoting stubs these ones
1324 // are NOT inserted by DoPrestub.
1326 if (((accessFlags & CORINFO_ACCESS_THIS) == 0) &&
1327 (pMethod->IsRemotingInterceptedViaVirtualDispatch()))
1332 // Methods with native callable attribute are special , since
1333 // they are used as LDFTN targets.Native Callable methods
1334 // uses the same code path as reverse pinvoke and embedding them
1335 // in an ngen image require saving the reverse pinvoke stubs.
1336 if (pMethod->HasNativeCallableAttribute())
1342 BOOL CEEPreloader::DoesMethodNeedRestoringBeforePrestubIsRun(
1343 CORINFO_METHOD_HANDLE methodHandle)
1345 STANDARD_VM_CONTRACT;
1347 MethodDesc * ftn = GetMethod(methodHandle);
1349 // The restore mechanism for InstantiatedMethodDescs (IMDs) is complicated, and causes
1350 // circular dependency complications with the GC if we hardbind to the prestub/precode
1351 // of an unrestored IMD. As such, we're eliminating hardbinding to unrestored MethodDescs
1352 // that belong to generic types.
1354 //@TODO: The reduction may be overkill, and we may consider refining the cases.
1356 // Specifically, InstantiatedMethodDescs can have preferred zap modules different than
1357 // the zap modules for their owning types. As such, in a soft-binding case a MethodDesc
1358 // may not be able to trace back to its owning Module without hitting an unrestored
1359 // fixup token. For example, the 64-bit JIT can not yet provide generic type arguments
1360 // and uses instantiating stubs to call static methods on generic types. If such an stub
1361 // belong to a module other than the module in which the generic type is declared, then
1362 // it is possible for the MethodTable::m_pEEClass or the EEClass::m_pModule pointers to
1363 // be unrestored. The complication arises when a call to the prestub/precode of such
1364 // an unrestored IMD causes us try to restore the IMD and this in turn causes us to
1365 // transition to preemptive GC and as such GC needs the metadata signature from the IMD
1366 // to iterate its arguments. But since we're currently restoring the IMD, we may not be
1367 // able to get to the signature, and as such we're stuck.
1369 // The same problem exists for instantiation arguments. We may need the instantiation
1370 // arguments while walking the signature during GC, and if they are not restored we're stuck.
1372 if (ftn->HasClassOrMethodInstantiation())
1374 if (ftn->NeedsRestore(m_image))
1381 BOOL CEECompileInfo::IsNativeCallableMethod(CORINFO_METHOD_HANDLE handle)
1383 WRAPPER_NO_CONTRACT;
1385 MethodDesc * pMethod = GetMethod(handle);
1386 return pMethod->HasNativeCallableAttribute();
1389 BOOL CEEPreloader::CanSkipDependencyActivation(CORINFO_METHOD_HANDLE context,
1390 CORINFO_MODULE_HANDLE moduleFrom,
1391 CORINFO_MODULE_HANDLE moduleTo)
1393 STANDARD_VM_CONTRACT;
1395 // Can't skip any fixups for speculative generic instantiations
1396 if (Module::GetPreferredZapModuleForMethodDesc(GetMethod(context)) != m_image->GetModule())
1399 // We don't need a fixup for eager bound dependencies since we are going to have
1400 // an uncontional one already.
1401 return m_image->CanEagerBindToModule((Module *)moduleTo);
1404 CORINFO_MODULE_HANDLE CEEPreloader::GetPreferredZapModuleForClassHandle(
1405 CORINFO_CLASS_HANDLE classHnd)
1407 STANDARD_VM_CONTRACT;
1409 return CORINFO_MODULE_HANDLE(Module::GetPreferredZapModuleForTypeHandle(TypeHandle(classHnd)));
1412 // This method is called directly from zapper
1413 extern BOOL CanDeduplicateCode(CORINFO_METHOD_HANDLE method, CORINFO_METHOD_HANDLE duplicateMethod);
1415 BOOL CanDeduplicateCode(CORINFO_METHOD_HANDLE method, CORINFO_METHOD_HANDLE duplicateMethod)
1424 ENABLE_FORBID_GC_LOADER_USE_IN_THIS_SCOPE();
1426 // For now, the deduplication is supported for IL stubs only
1427 DynamicMethodDesc * pMethod = GetMethod(method)->AsDynamicMethodDesc();
1428 DynamicMethodDesc * pDuplicateMethod = GetMethod(duplicateMethod)->AsDynamicMethodDesc();
1431 // Make sure that the return types match (for code:Thread::HijackThread)
1435 MetaSig msig1(pMethod);
1436 MetaSig msig2(pDuplicateMethod);
1437 if (!msig1.HasFPReturn() != !msig2.HasFPReturn())
1439 #endif // _TARGET_X86_
1441 MetaSig::RETURNTYPE returnType = pMethod->ReturnsObject();
1442 MetaSig::RETURNTYPE returnTypeDuplicate = pDuplicateMethod->ReturnsObject();
1444 if (returnType != returnTypeDuplicate)
1448 // Do not enable deduplication of structs returned in registers
1451 if (returnType == MetaSig::RETVALUETYPE)
1455 // Make sure that the IL stub flags match
1458 if (pMethod->GetExtendedFlags() != pDuplicateMethod->GetExtendedFlags())
1464 void CEEPreloader::NoteDeduplicatedCode(CORINFO_METHOD_HANDLE method, CORINFO_METHOD_HANDLE duplicateMethod)
1466 STANDARD_VM_CONTRACT;
1468 #ifndef FEATURE_FULL_NGEN // Deduplication
1469 DuplicateMethodEntry e;
1470 e.pMD = GetMethod(method);
1471 e.pDuplicateMD = GetMethod(duplicateMethod);
1472 m_duplicateMethodsHash.Add(e);
1476 HRESULT CEECompileInfo::GetFieldDef(CORINFO_FIELD_HANDLE fieldHandle,
1479 STANDARD_VM_CONTRACT;
1481 CANNOTTHROWCOMPLUSEXCEPTION();
1483 *token = ((FieldDesc*)fieldHandle)->GetMemberDef();
1488 void CEECompileInfo::EncodeModuleAsIndexes(CORINFO_MODULE_HANDLE fromHandle,
1489 CORINFO_MODULE_HANDLE handle,
1490 DWORD* pAssemblyIndex,
1491 DWORD* pModuleIndex,
1492 IMetaDataAssemblyEmit* pAssemblyEmit)
1494 STANDARD_VM_CONTRACT;
1496 COOPERATIVE_TRANSITION_BEGIN();
1498 Module *fromModule = GetModule(fromHandle);
1499 Assembly *fromAssembly = fromModule->GetAssembly();
1501 Module *module = GetModule(handle);
1502 Assembly *assembly = module->GetAssembly();
1504 if (assembly == fromAssembly)
1505 *pAssemblyIndex = 0;
1511 CompilationDomain *pDomain = GetAppDomain()->ToCompilationDomain();
1513 RefCache *pRefCache = pDomain->GetRefCache(fromModule);
1518 if (!assembly->GetManifestFile()->HasBindableIdentity())
1520 // If the module that we'd like to encode for a later fixup doesn't have
1521 // a bindable identity, then this will fail at runtime. So, we ask the
1522 // compilation domain for a matching assembly with a bindable identity.
1523 // This is possible because this module must have been bound in the past,
1524 // and the compilation domain will keep track of at least one corresponding
1525 // bindable identity.
1526 AssemblySpec defSpec;
1527 defSpec.InitializeSpec(assembly->GetManifestFile());
1529 AssemblySpec* pRefSpec = pDomain->FindAssemblyRefSpecForDefSpec(&defSpec);
1530 _ASSERTE(pRefSpec != nullptr);
1532 IfFailThrow(pRefSpec->EmitToken(pAssemblyEmit, &token, TRUE, TRUE));
1533 token += fromModule->GetAssemblyRefMax();
1537 result = pRefCache->m_sAssemblyRefMap.LookupValue((UPTR)assembly, NULL);
1539 if (result == (UPTR)INVALIDENTRY)
1540 token = fromModule->FindAssemblyRef(assembly);
1542 token = (mdAssemblyRef) result;
1544 if (IsNilToken(token))
1546 token = fromAssembly->AddAssemblyRef(assembly, pAssemblyEmit);
1547 token += fromModule->GetAssemblyRefMax();
1551 *pAssemblyIndex = RidFromToken(token);
1553 pRefCache->m_sAssemblyRefMap.InsertValue((UPTR) assembly, (UPTR)token);
1556 if (module == assembly->GetManifestModule())
1560 _ASSERTE(module->GetModuleRef() != mdFileNil);
1561 *pModuleIndex = RidFromToken(module->GetModuleRef());
1564 COOPERATIVE_TRANSITION_END();
1567 void CEECompileInfo::EncodeClass(
1568 CORINFO_MODULE_HANDLE referencingModule,
1569 CORINFO_CLASS_HANDLE classHandle,
1570 SigBuilder * pSigBuilder,
1571 LPVOID pEncodeModuleContext,
1572 ENCODEMODULE_CALLBACK pfnEncodeModule)
1574 STANDARD_VM_CONTRACT;
1576 TypeHandle th(classHandle);
1578 ZapSig zapSig((Module *)referencingModule, pEncodeModuleContext, ZapSig::NormalTokens,
1579 (EncodeModuleCallback) pfnEncodeModule, NULL);
1581 COOPERATIVE_TRANSITION_BEGIN();
1584 fSuccess = zapSig.GetSignatureForTypeHandle(th, pSigBuilder);
1587 COOPERATIVE_TRANSITION_END();
1590 CORINFO_MODULE_HANDLE CEECompileInfo::GetLoaderModuleForMscorlib()
1592 STANDARD_VM_CONTRACT;
1594 return CORINFO_MODULE_HANDLE(SystemDomain::SystemModule());
1597 CORINFO_MODULE_HANDLE CEECompileInfo::GetLoaderModuleForEmbeddableType(CORINFO_CLASS_HANDLE clsHnd)
1599 STANDARD_VM_CONTRACT;
1601 TypeHandle t = TypeHandle(clsHnd);
1602 return CORINFO_MODULE_HANDLE(t.GetLoaderModule());
1605 CORINFO_MODULE_HANDLE CEECompileInfo::GetLoaderModuleForEmbeddableMethod(CORINFO_METHOD_HANDLE methHnd)
1607 STANDARD_VM_CONTRACT;
1609 MethodDesc *pMD = GetMethod(methHnd);
1610 return CORINFO_MODULE_HANDLE(pMD->GetLoaderModule());
1613 CORINFO_MODULE_HANDLE CEECompileInfo::GetLoaderModuleForEmbeddableField(CORINFO_FIELD_HANDLE fieldHnd)
1615 STANDARD_VM_CONTRACT;
1617 FieldDesc *pFD = (FieldDesc *) fieldHnd;
1618 return CORINFO_MODULE_HANDLE(pFD->GetLoaderModule());
1621 void CEECompileInfo::EncodeMethod(
1622 CORINFO_MODULE_HANDLE referencingModule,
1623 CORINFO_METHOD_HANDLE handle,
1624 SigBuilder * pSigBuilder,
1625 LPVOID pEncodeModuleContext,
1626 ENCODEMODULE_CALLBACK pfnEncodeModule,
1627 CORINFO_RESOLVED_TOKEN * pResolvedToken,
1628 CORINFO_RESOLVED_TOKEN * pConstrainedResolvedToken,
1629 BOOL fEncodeUsingResolvedTokenSpecStreams)
1631 STANDARD_VM_CONTRACT;
1633 COOPERATIVE_TRANSITION_BEGIN();
1634 MethodDesc *pMethod = GetMethod(handle);
1637 fSuccess = ZapSig::EncodeMethod(pMethod,
1638 (Module *) referencingModule,
1640 pEncodeModuleContext,
1641 pfnEncodeModule, NULL,
1642 pResolvedToken, pConstrainedResolvedToken,
1643 fEncodeUsingResolvedTokenSpecStreams);
1646 COOPERATIVE_TRANSITION_END();
1649 mdToken CEECompileInfo::TryEncodeMethodAsToken(
1650 CORINFO_METHOD_HANDLE handle,
1651 CORINFO_RESOLVED_TOKEN * pResolvedToken,
1652 CORINFO_MODULE_HANDLE * referencingModule)
1654 STANDARD_VM_CONTRACT;
1656 MethodDesc * pMethod = GetMethod(handle);
1658 #ifdef FEATURE_READYTORUN_COMPILER
1659 if (IsReadyToRunCompilation())
1661 _ASSERTE(pResolvedToken != NULL);
1663 Module * pReferencingModule = (Module *)pResolvedToken->tokenScope;
1665 if (!pReferencingModule->IsInCurrentVersionBubble())
1668 // If this is a MemberRef with TypeSpec, we might come to here because we resolved the method
1669 // into a non-generic base class in the same version bubble. However, since we don't have the
1670 // proper type context during ExternalMethodFixupWorker, we can't really encode using token
1671 if (pResolvedToken->pTypeSpec != NULL)
1674 unsigned methodToken = pResolvedToken->token;
1676 switch (TypeFromToken(methodToken))
1679 if (pReferencingModule->LookupMethodDef(methodToken) != pMethod)
1684 if (pReferencingModule->LookupMemberRefAsMethod(methodToken) != pMethod)
1692 *referencingModule = CORINFO_MODULE_HANDLE(pReferencingModule);
1695 #endif // FEATURE_READYTORUN_COMPILER
1697 Module *pModule = pMethod->GetModule();
1698 if (!pModule->IsInCurrentVersionBubble())
1700 Module * pTargetModule = GetAppDomain()->ToCompilationDomain()->GetTargetModule();
1701 *referencingModule = CORINFO_MODULE_HANDLE(pTargetModule);
1702 return pTargetModule->LookupMemberRefByMethodDesc(pMethod);
1706 mdToken defToken = pMethod->GetMemberDef();
1707 if (pModule->LookupMethodDef(defToken) == pMethod)
1709 *referencingModule = CORINFO_MODULE_HANDLE(pModule);
1717 DWORD CEECompileInfo::TryEncodeMethodSlot(CORINFO_METHOD_HANDLE handle)
1719 STANDARD_VM_CONTRACT;
1721 MethodDesc * pMethod = GetMethod(handle);
1723 #ifdef FEATURE_READYTORUN_COMPILER
1724 if (IsReadyToRunCompilation())
1726 // We can only encode real interface methods as slots
1727 if (!pMethod->IsInterface() || pMethod->IsStatic())
1730 // And only if the interface lives in the current version bubble
1731 // If may be possible to relax this restriction if we can guarantee that the external interfaces are
1732 // really not changing. We will play it safe for now.
1733 if (!pMethod->GetModule()->IsInCurrentVersionBubble())
1738 return pMethod->GetSlot();
1741 void EncodeTypeInDictionarySignature(
1742 Module * pInfoModule,
1744 SigBuilder * pSigBuilder,
1745 LPVOID encodeContext,
1746 ENCODEMODULE_CALLBACK pfnEncodeModule)
1748 STANDARD_VM_CONTRACT;
1750 CorElementType typ = ELEMENT_TYPE_END;
1751 IfFailThrow(ptr.GetElemType(&typ));
1753 if (typ == ELEMENT_TYPE_INTERNAL)
1757 IfFailThrow(ptr.GetPointer((void**)&th));
1759 ZapSig zapSig(pInfoModule, encodeContext, ZapSig::NormalTokens,
1760 (EncodeModuleCallback) pfnEncodeModule, NULL);
1766 fSuccess = zapSig.GetSignatureForTypeHandle(th, pSigBuilder);
1772 if (typ == ELEMENT_TYPE_GENERICINST)
1775 // SigParser expects ELEMENT_TYPE_MODULE_ZAPSIG to be before ELEMENT_TYPE_GENERICINST
1777 SigPointer peek(ptr);
1779 IfFailThrow(peek.GetData(&instType));
1780 _ASSERTE(instType == ELEMENT_TYPE_INTERNAL);
1783 IfFailThrow(peek.GetPointer((void **)&th));
1785 Module * pTypeHandleModule = th.GetModule();
1787 if (!pTypeHandleModule->IsInCurrentVersionBubble())
1789 pTypeHandleModule = GetAppDomain()->ToCompilationDomain()->GetTargetModule();
1792 if (pTypeHandleModule != pInfoModule)
1794 DWORD index = pfnEncodeModule(encodeContext, (CORINFO_MODULE_HANDLE)pTypeHandleModule);
1795 _ASSERTE(index != ENCODE_MODULE_FAILED);
1797 pSigBuilder->AppendElementType((CorElementType) ELEMENT_TYPE_MODULE_ZAPSIG);
1798 pSigBuilder->AppendData(index);
1801 pSigBuilder->AppendElementType(ELEMENT_TYPE_GENERICINST);
1803 EncodeTypeInDictionarySignature(pTypeHandleModule, ptr, pSigBuilder, encodeContext, pfnEncodeModule);
1804 IfFailThrow(ptr.SkipExactlyOne());
1806 ULONG argCnt = 0; // Get number of parameters
1807 IfFailThrow(ptr.GetData(&argCnt));
1808 pSigBuilder->AppendData(argCnt);
1812 EncodeTypeInDictionarySignature(pInfoModule, ptr, pSigBuilder, encodeContext, pfnEncodeModule);
1813 IfFailThrow(ptr.SkipExactlyOne());
1818 else if((CorElementTypeZapSig)typ == ELEMENT_TYPE_NATIVE_ARRAY_TEMPLATE_ZAPSIG)
1820 pSigBuilder->AppendElementType((CorElementType)ELEMENT_TYPE_NATIVE_ARRAY_TEMPLATE_ZAPSIG);
1822 IfFailThrow(ptr.GetElemType(&typ));
1824 _ASSERTE(typ == ELEMENT_TYPE_SZARRAY || typ == ELEMENT_TYPE_ARRAY);
1827 pSigBuilder->AppendElementType(typ);
1829 if (!CorIsPrimitiveType(typ))
1833 case ELEMENT_TYPE_VAR:
1834 case ELEMENT_TYPE_MVAR:
1837 // Skip variable number
1838 IfFailThrow(ptr.GetData(&varNum));
1839 pSigBuilder->AppendData(varNum);
1842 case ELEMENT_TYPE_OBJECT:
1843 case ELEMENT_TYPE_STRING:
1844 case ELEMENT_TYPE_TYPEDBYREF:
1847 case ELEMENT_TYPE_BYREF: //fallthru
1848 case ELEMENT_TYPE_PTR:
1849 case ELEMENT_TYPE_PINNED:
1850 case ELEMENT_TYPE_SZARRAY:
1851 EncodeTypeInDictionarySignature(pInfoModule, ptr, pSigBuilder, encodeContext, pfnEncodeModule);
1852 IfFailThrow(ptr.SkipExactlyOne());
1855 case ELEMENT_TYPE_ARRAY:
1857 EncodeTypeInDictionarySignature(pInfoModule, ptr, pSigBuilder, encodeContext, pfnEncodeModule);
1858 IfFailThrow(ptr.SkipExactlyOne());
1860 ULONG rank = 0; // Get rank
1861 IfFailThrow(ptr.GetData(&rank));
1862 pSigBuilder->AppendData(rank);
1867 IfFailThrow(ptr.GetData(&nsizes));
1868 pSigBuilder->AppendData(nsizes);
1873 IfFailThrow(ptr.GetData(&data));
1874 pSigBuilder->AppendData(data);
1878 IfFailThrow(ptr.GetData(&nlbounds));
1879 pSigBuilder->AppendData(nlbounds);
1884 IfFailThrow(ptr.GetData(&data));
1885 pSigBuilder->AppendData(data);
1892 _ASSERTE(!"Unexpected element in signature");
1897 void CEECompileInfo::EncodeGenericSignature(
1900 SigBuilder * pSigBuilder,
1901 LPVOID encodeContext,
1902 ENCODEMODULE_CALLBACK pfnEncodeModule)
1904 STANDARD_VM_CONTRACT;
1906 Module * pInfoModule = MscorlibBinder::GetModule();
1908 SigPointer ptr((PCCOR_SIGNATURE)signature);
1910 ULONG entryKind; // DictionaryEntryKind
1911 IfFailThrow(ptr.GetData(&entryKind));
1912 pSigBuilder->AppendData(entryKind);
1916 ULONG dictionaryIndex = 0;
1917 IfFailThrow(ptr.GetData(&dictionaryIndex));
1919 pSigBuilder->AppendData(dictionaryIndex);
1924 case DeclaringTypeHandleSlot:
1925 EncodeTypeInDictionarySignature(pInfoModule, ptr, pSigBuilder, encodeContext, pfnEncodeModule);
1926 IfFailThrow(ptr.SkipExactlyOne());
1929 case TypeHandleSlot:
1930 EncodeTypeInDictionarySignature(pInfoModule, ptr, pSigBuilder, encodeContext, pfnEncodeModule);
1931 IfFailThrow(ptr.SkipExactlyOne());
1934 case ConstrainedMethodEntrySlot:
1935 EncodeTypeInDictionarySignature(pInfoModule, ptr, pSigBuilder, encodeContext, pfnEncodeModule);
1936 IfFailThrow(ptr.SkipExactlyOne());
1939 case MethodDescSlot:
1940 case MethodEntrySlot:
1941 case DispatchStubAddrSlot:
1943 EncodeTypeInDictionarySignature(pInfoModule, ptr, pSigBuilder, encodeContext, pfnEncodeModule);
1944 IfFailThrow(ptr.SkipExactlyOne());
1947 IfFailThrow(ptr.GetData(&methodFlags));
1948 pSigBuilder->AppendData(methodFlags);
1950 if ((methodFlags & ENCODE_METHOD_SIG_SlotInsteadOfToken) == 0)
1952 EncodeTypeInDictionarySignature(pInfoModule, ptr, pSigBuilder, encodeContext, pfnEncodeModule);
1953 IfFailThrow(ptr.SkipExactlyOne());
1957 IfFailThrow(ptr.GetData(&tokenOrSlot));
1958 pSigBuilder->AppendData(tokenOrSlot);
1960 if (methodFlags & ENCODE_METHOD_SIG_MethodInstantiation)
1962 DWORD nGenericMethodArgs;
1963 IfFailThrow(ptr.GetData(&nGenericMethodArgs));
1964 pSigBuilder->AppendData(nGenericMethodArgs);
1966 for (DWORD i = 0; i < nGenericMethodArgs; i++)
1968 EncodeTypeInDictionarySignature(pInfoModule, ptr, pSigBuilder, encodeContext, pfnEncodeModule);
1969 IfFailThrow(ptr.SkipExactlyOne());
1977 EncodeTypeInDictionarySignature(pInfoModule, ptr, pSigBuilder, encodeContext, pfnEncodeModule);
1978 IfFailThrow(ptr.SkipExactlyOne());
1981 IfFailThrow(ptr.GetData(&fieldIndex));
1982 pSigBuilder->AppendData(fieldIndex);
1990 ULONG dictionarySlot;
1991 IfFailThrow(ptr.GetData(&dictionarySlot));
1992 pSigBuilder->AppendData(dictionarySlot);
1995 void CEECompileInfo::EncodeField(
1996 CORINFO_MODULE_HANDLE referencingModule,
1997 CORINFO_FIELD_HANDLE handle,
1998 SigBuilder * pSigBuilder,
1999 LPVOID encodeContext,
2000 ENCODEMODULE_CALLBACK pfnEncodeModule,
2001 CORINFO_RESOLVED_TOKEN * pResolvedToken,
2002 BOOL fEncodeUsingResolvedTokenSpecStreams)
2004 STANDARD_VM_CONTRACT;
2006 COOPERATIVE_TRANSITION_BEGIN();
2008 ZapSig::EncodeField(GetField(handle),
2009 (Module *) referencingModule,
2014 fEncodeUsingResolvedTokenSpecStreams);
2016 COOPERATIVE_TRANSITION_END();
2019 BOOL CEECompileInfo::IsEmptyString(mdString token,
2020 CORINFO_MODULE_HANDLE module)
2022 STANDARD_VM_CONTRACT;
2026 COOPERATIVE_TRANSITION_BEGIN();
2028 EEStringData strData;
2029 ((Module *)module)->InitializeStringData(token, &strData, NULL);
2030 fRet = (strData.GetCharCount() == 0);
2032 COOPERATIVE_TRANSITION_END();
2037 #ifdef FEATURE_READYTORUN_COMPILER
2038 CORCOMPILE_FIXUP_BLOB_KIND CEECompileInfo::GetFieldBaseOffset(
2039 CORINFO_CLASS_HANDLE classHnd,
2040 DWORD * pBaseOffset)
2042 STANDARD_VM_CONTRACT;
2044 MethodTable * pMT = (MethodTable *)classHnd;
2045 Module * pModule = pMT->GetModule();
2047 if (!pMT->IsLayoutFixedInCurrentVersionBubble())
2049 return pMT->IsValueType() ? ENCODE_CHECK_FIELD_OFFSET : ENCODE_FIELD_OFFSET;
2052 if (pMT->IsValueType())
2057 if (pMT->GetParentMethodTable()->IsInheritanceChainLayoutFixedInCurrentVersionBubble())
2062 if (pMT->HasLayout())
2064 // We won't try to be smart for classes with layout.
2065 // They are complex to get right, and very rare anyway.
2066 return ENCODE_FIELD_OFFSET;
2069 *pBaseOffset = ReadyToRunInfo::GetFieldBaseOffset(pMT);
2070 return ENCODE_FIELD_BASE_OFFSET;
2073 BOOL CEECompileInfo::NeedsTypeLayoutCheck(CORINFO_CLASS_HANDLE classHnd)
2075 STANDARD_VM_CONTRACT;
2077 TypeHandle th(classHnd);
2079 if (th.IsTypeDesc())
2082 MethodTable * pMT = th.AsMethodTable();
2084 if (!pMT->IsValueType())
2087 // Skip this check for equivalent types. Equivalent types are used for interop that ensures
2089 if (pMT->GetClass()->IsEquivalentType())
2092 return !pMT->IsLayoutFixedInCurrentVersionBubble();
2095 extern void ComputeGCRefMap(MethodTable * pMT, BYTE * pGCRefMap, size_t cbGCRefMap);
2097 void CEECompileInfo::EncodeTypeLayout(CORINFO_CLASS_HANDLE classHandle, SigBuilder * pSigBuilder)
2099 STANDARD_VM_CONTRACT;
2101 MethodTable * pMT = TypeHandle(classHandle).AsMethodTable();
2102 _ASSERTE(pMT->IsValueType());
2104 DWORD dwSize = pMT->GetNumInstanceFieldBytes();
2105 DWORD dwAlignment = CEEInfo::getClassAlignmentRequirementStatic(pMT);
2111 dwFlags |= READYTORUN_LAYOUT_HFA;
2115 dwFlags |= READYTORUN_LAYOUT_Alignment;
2116 if (dwAlignment == sizeof(void *))
2117 dwFlags |= READYTORUN_LAYOUT_Alignment_Native;
2119 dwFlags |= READYTORUN_LAYOUT_GCLayout;
2120 if (!pMT->ContainsPointers())
2121 dwFlags |= READYTORUN_LAYOUT_GCLayout_Empty;
2123 pSigBuilder->AppendData(dwFlags);
2125 // Size is checked unconditionally
2126 pSigBuilder->AppendData(dwSize);
2129 if (dwFlags & READYTORUN_LAYOUT_HFA)
2131 pSigBuilder->AppendData(pMT->GetHFAType());
2135 if ((dwFlags & READYTORUN_LAYOUT_Alignment) && !(dwFlags & READYTORUN_LAYOUT_Alignment_Native))
2137 pSigBuilder->AppendData(dwAlignment);
2140 if ((dwFlags & READYTORUN_LAYOUT_GCLayout) && !(dwFlags & READYTORUN_LAYOUT_GCLayout_Empty))
2142 size_t cbGCRefMap = (dwSize / sizeof(TADDR) + 7) / 8;
2143 _ASSERTE(cbGCRefMap > 0);
2145 BYTE * pGCRefMap = (BYTE *)_alloca(cbGCRefMap);
2147 ComputeGCRefMap(pMT, pGCRefMap, cbGCRefMap);
2149 for (size_t i = 0; i < cbGCRefMap; i++)
2150 pSigBuilder->AppendByte(pGCRefMap[i]);
2154 BOOL CEECompileInfo::AreAllClassesFullyLoaded(CORINFO_MODULE_HANDLE moduleHandle)
2156 STANDARD_VM_CONTRACT;
2158 return ((Module *)moduleHandle)->AreAllClassesFullyLoaded();
2161 int CEECompileInfo::GetVersionResilientTypeHashCode(CORINFO_MODULE_HANDLE moduleHandle, mdToken token)
2163 STANDARD_VM_CONTRACT;
2166 if (!::GetVersionResilientTypeHashCode(((Module *)moduleHandle)->GetMDImport(), token, &dwHashCode))
2167 ThrowHR(COR_E_BADIMAGEFORMAT);
2172 int CEECompileInfo::GetVersionResilientMethodHashCode(CORINFO_METHOD_HANDLE methodHandle)
2174 STANDARD_VM_CONTRACT;
2176 return ::GetVersionResilientMethodHashCode(GetMethod(methodHandle));
2179 #endif // FEATURE_READYTORUN_COMPILER
2181 BOOL CEECompileInfo::HasCustomAttribute(CORINFO_METHOD_HANDLE method, LPCSTR customAttributeName)
2183 STANDARD_VM_CONTRACT;
2185 MethodDesc * pMD = GetMethod(method);
2186 return S_OK == pMD->GetMDImport()->GetCustomAttributeByName(pMD->GetMemberDef(), customAttributeName, NULL, NULL);
2189 #define OMFConst_Read 0x0001
2190 #define OMFConst_Write 0x0002
2191 #define OMFConst_Exec 0x0004
2192 #define OMFConst_F32Bit 0x0008
2193 #define OMFConst_ReservedBits1 0x00f0
2194 #define OMFConst_FSel 0x0100
2195 #define OMFConst_FAbs 0x0200
2196 #define OMFConst_ReservedBits2 0x0C00
2197 #define OMFConst_FGroup 0x1000
2198 #define OMFConst_ReservedBits3 0xE000
2200 #define OMF_StandardText (OMFConst_FSel|OMFConst_F32Bit|OMFConst_Exec|OMFConst_Read) // 0x10D
2201 #define OMF_SentinelType (OMFConst_FAbs|OMFConst_F32Bit) // 0x208
2204 // ----------------------------------------------------------------------------
2207 // The NGEN PDB format consists of structs stacked together into buffers, which are
2208 // passed to the PDB API. For a description of the structures, see
2209 // InternalApis\vctools\inc\cvinfo.h.
2211 // The interface to the PDB used below is NGEN-specific, and is exposed via
2212 // diasymreader.dll. For a description of this interface, see ISymNGenWriter2 inside
2213 // public\devdiv\inc\corsym.h and debugger\sh\symwrtr\ngenpdbwriter.h,cpp
2214 // ----------------------------------------------------------------------------
2216 #if defined(NO_NGENPDB) && !defined(FEATURE_PERFMAP)
2217 BOOL CEECompileInfo::GetIsGeneratingNgenPDB()
2222 void CEECompileInfo::SetIsGeneratingNgenPDB(BOOL fGeneratingNgenPDB)
2226 BOOL IsNgenPDBCompilationProcess()
2231 BOOL CEECompileInfo::GetIsGeneratingNgenPDB()
2233 LIMITED_METHOD_DAC_CONTRACT;
2234 return m_fGeneratingNgenPDB;
2237 void CEECompileInfo::SetIsGeneratingNgenPDB(BOOL fGeneratingNgenPDB)
2239 LIMITED_METHOD_DAC_CONTRACT;
2240 m_fGeneratingNgenPDB = fGeneratingNgenPDB;
2243 BOOL IsNgenPDBCompilationProcess()
2245 LIMITED_METHOD_DAC_CONTRACT;
2246 return IsCompilationProcess() && g_pCEECompileInfo->GetIsGeneratingNgenPDB();
2249 #endif // NO_NGENPDB && !FEATURE_PERFMAP
2252 // This is the prototype of "CreateNGenPdbWriter" exported by diasymreader.dll
2253 typedef HRESULT (__stdcall *CreateNGenPdbWriter_t)(const WCHAR *pwszNGenImagePath, const WCHAR *pwszPdbPath, void **ppvObj);
2255 // Allocator to specify when requesting boundaries information for PDB
2256 BYTE* SimpleNew(void *, size_t cBytes)
2266 BYTE * p = new BYTE[cBytes];
2270 // PDB convention has any IPs that don't map to source code (e.g., prolog, epilog, etc.)
2271 // to be mapped to line number "0xFeeFee".
2272 const int kUnmappedIP = 0xFeeFee;
2275 // ----------------------------------------------------------------------------
2276 // Simple pair of offsets for each source file name. Pair includes its offset into the
2277 // PDB string table, and its offset in the files checksum table.
2279 struct DocNameOffsets
2281 ULONG32 m_dwStrTableOffset;
2282 ULONG32 m_dwChksumTableOffset;
2283 DocNameOffsets(ULONG32 dwStrTableOffset, ULONG32 dwChksumTableOffset)
2284 : m_dwStrTableOffset(dwStrTableOffset), m_dwChksumTableOffset(dwChksumTableOffset)
2286 LIMITED_METHOD_CONTRACT;
2290 : m_dwStrTableOffset((ULONG32) -1), m_dwChksumTableOffset((ULONG32) -1)
2292 LIMITED_METHOD_CONTRACT;
2297 // ----------------------------------------------------------------------------
2298 // This is used when creating the hash table which maps source file names to
2299 // DocNameOffsets instances. The only interesting stuff here is that:
2300 // * Equality is determined by a case-insensitive comparison on the source file
2302 // * Hashing is done by hashing the source file names
2304 struct DocNameToOffsetMapTraits : public NoRemoveSHashTraits < MapSHashTraits<LPCSTR, DocNameOffsets> >
2307 static BOOL Equals(key_t k1, key_t k2)
2309 LIMITED_METHOD_CONTRACT;
2311 if (k1 == NULL && k2 == NULL)
2313 if (k1 == NULL || k2 == NULL)
2315 return _stricmp(k1, k2) == 0;
2318 static count_t Hash(key_t k)
2320 LIMITED_METHOD_CONTRACT;
2325 return HashiStringA(k);
2329 typedef DocNameOffsets VALUE;
2330 typedef NoRemoveSHashTraits < MapSHashTraits<LPCSTR, DocNameOffsets> > PARENT;
2331 typedef PARENT::element_t element_t;
2332 static const element_t Null() { LIMITED_METHOD_CONTRACT; return element_t((KEY)0,VALUE((ULONG32) -1, (ULONG32) -1)); }
2333 static bool IsNull(const element_t &e) { LIMITED_METHOD_CONTRACT; return e.Key() == (KEY)0; }
2337 // ----------------------------------------------------------------------------
2338 // Hash table that maps the UTF-8 string of a source file name to its corresponding
2339 // DocNameToOffsetMapTraits
2341 class DocNameToOffsetMap : public SHash<DocNameToOffsetMapTraits>
2343 typedef SHash<DocNameToOffsetMapTraits> PARENT;
2345 typedef DocNameOffsets VALUE;
2348 void Add(KEY key, VALUE value)
2354 PRECONDITION(key != (KEY)0);
2358 PARENT::Add(KeyValuePair<KEY,VALUE>(key, value));
2361 void AddOrReplace(KEY key, VALUE value)
2367 PRECONDITION(key != (KEY)0);
2371 PARENT::AddOrReplace(KeyValuePair<KEY,VALUE>(key, value));
2374 BOOL Lookup(KEY key, VALUE* pValue)
2380 PRECONDITION(key != (KEY)0);
2384 const KeyValuePair<KEY,VALUE> *pRet = PARENT::LookupPtr(key);
2388 *pValue = pRet->Value();
2393 // ----------------------------------------------------------------------------
2394 // Simple class to sort ICorDebugInfo::OffsetMapping arrays by IL offset
2396 class QuickSortILNativeMapByIL : public CQuickSort<ICorDebugInfo::OffsetMapping>
2399 QuickSortILNativeMapByIL(
2400 ICorDebugInfo::OffsetMapping * rgMap,
2402 : CQuickSort<ICorDebugInfo::OffsetMapping>(rgMap, cEntries)
2404 LIMITED_METHOD_CONTRACT;
2407 int Compare(ICorDebugInfo::OffsetMapping * pFirst,
2408 ICorDebugInfo::OffsetMapping * pSecond)
2410 LIMITED_METHOD_CONTRACT;
2412 if (pFirst->ilOffset < pSecond->ilOffset)
2414 else if (pFirst->ilOffset == pSecond->ilOffset)
2421 // ----------------------------------------------------------------------------
2422 // Simple class to sort IL to Native mapping arrays by Native offset
2424 class QuickSortILNativeMapByNativeOffset : public CQuickSort<ICorDebugInfo::OffsetMapping>
2427 QuickSortILNativeMapByNativeOffset(
2428 ICorDebugInfo::OffsetMapping * rgMap,
2430 : CQuickSort<ICorDebugInfo::OffsetMapping>(rgMap, cEntries)
2432 LIMITED_METHOD_CONTRACT;
2435 int Compare(ICorDebugInfo::OffsetMapping * pFirst,
2436 ICorDebugInfo::OffsetMapping * pSecond)
2438 LIMITED_METHOD_CONTRACT;
2440 if (pFirst->nativeOffset < pSecond->nativeOffset)
2442 else if (pFirst->nativeOffset == pSecond->nativeOffset)
2449 // ----------------------------------------------------------------------------
2450 // Simple structure used when merging the JIT manager's IL-to-native maps
2451 // (ICorDebugInfo::OffsetMapping) with the IL PDB's source-to-IL map.
2456 // Index into ICorDebugInfo::OffsetMapping
2457 ULONG32 m_iIlNativeMap;
2459 // Corresponding index into the IL PDB's sequence point arrays
2460 ULONG32 m_iSeqPoints;
2463 m_iIlNativeMap((ULONG32) -1),
2464 m_iSeqPoints((ULONG32) -1)
2466 LIMITED_METHOD_CONTRACT;
2470 // ----------------------------------------------------------------------------
2471 // Simple class to sort MapIndexPairs by native IP offset. A MapIndexPair sorts "earlier"
2472 // if its m_iIlNativeMap index gives you an IP offset (i.e.,
2473 // m_rgIlNativeMap[m_iIlNativeMap].nativeOffset) that is smaller.
2475 class QuickSortMapIndexPairsByNativeOffset : public CQuickSort<MapIndexPair>
2478 QuickSortMapIndexPairsByNativeOffset(
2479 MapIndexPair * rgMap,
2481 ICorDebugInfo::OffsetMapping * rgIlNativeMap,
2482 ULONG32 cIlNativeMap)
2483 : CQuickSort<MapIndexPair>(rgMap, cEntries),
2484 m_rgIlNativeMap(rgIlNativeMap),
2485 m_cIlNativeMap(cIlNativeMap)
2487 LIMITED_METHOD_CONTRACT;
2490 int Compare(MapIndexPair * pFirst,
2491 MapIndexPair * pSecond)
2493 LIMITED_METHOD_CONTRACT;
2495 _ASSERTE(pFirst->m_iIlNativeMap < m_cIlNativeMap);
2496 _ASSERTE(pSecond->m_iIlNativeMap < m_cIlNativeMap);
2498 DWORD dwFirstNativeOffset = m_rgIlNativeMap[pFirst->m_iIlNativeMap].nativeOffset;
2499 DWORD dwSecondNativeOffset = m_rgIlNativeMap[pSecond->m_iIlNativeMap].nativeOffset;
2501 if (dwFirstNativeOffset < dwSecondNativeOffset)
2503 else if (dwFirstNativeOffset == dwSecondNativeOffset)
2510 ICorDebugInfo::OffsetMapping * m_rgIlNativeMap;
2511 ULONG32 m_cIlNativeMap;
2514 // ----------------------------------------------------------------------------
2515 // The following 3 classes contain the code to generate PDBs
2518 // NGEN always generates PDBs with public symbols lists (so tools can map IP ranges to
2519 // methods). This bitmask indicates what extra info should be added to the PDB
2522 // Add string table subsection, files checksum subsection, and lines subsection to
2523 // allow tools to map IP ranges to source lines.
2524 kPDBLines = 0x00000001,
2528 // ----------------------------------------------------------------------------
2529 // Manages generating all PDB data for an NGENd image. One of these is instantiated per
2530 // run of "ngen createpdb"
2535 CreateNGenPdbWriter_t m_Create;
2537 ReleaseHolder<ISymUnmanagedBinder> m_pBinder;
2538 LPCWSTR m_wszPdbPath;
2539 DWORD m_dwExtraData;
2540 LPCWSTR m_wszManagedPDBSearchPath;
2543 NGenPdbWriter (LPCWSTR wszNativeImagePath, LPCWSTR wszPdbPath, DWORD dwExtraData, LPCWSTR wszManagedPDBSearchPath)
2546 m_wszPdbPath(wszPdbPath),
2547 m_dwExtraData(dwExtraData),
2548 m_wszManagedPDBSearchPath(wszManagedPDBSearchPath)
2550 LIMITED_METHOD_CONTRACT;
2553 #define WRITER_LOAD_ERROR_MESSAGE W("Unable to load ") NATIVE_SYMBOL_READER_DLL W(". Please ensure that ") NATIVE_SYMBOL_READER_DLL W(" is on the path. Error='%d'\n")
2555 HRESULT Load(LPCWSTR wszDiasymreaderPath = nullptr)
2557 STANDARD_VM_CONTRACT;
2561 m_hModule = WszLoadLibrary(wszDiasymreaderPath != nullptr ? wszDiasymreaderPath : (LPCWSTR)NATIVE_SYMBOL_READER_DLL);
2562 if (m_hModule == NULL)
2564 hr = HRESULT_FROM_WIN32(GetLastError());
2565 GetSvcLogger()->Printf(WRITER_LOAD_ERROR_MESSAGE, GetLastError());
2569 m_Create = reinterpret_cast<CreateNGenPdbWriter_t>(GetProcAddress(m_hModule, "CreateNGenPdbWriter"));
2570 if (m_Create == NULL)
2572 hr = HRESULT_FROM_WIN32(GetLastError());
2573 GetSvcLogger()->Printf(WRITER_LOAD_ERROR_MESSAGE, GetLastError());
2577 if ((m_dwExtraData & kPDBLines) != 0)
2579 hr = FakeCoCreateInstanceEx(
2580 CLSID_CorSymBinder_SxS,
2581 wszDiasymreaderPath != nullptr ? wszDiasymreaderPath : (LPCWSTR)NATIVE_SYMBOL_READER_DLL,
2582 IID_ISymUnmanagedBinder,
2590 HRESULT WritePDBDataForModule(Module * pModule);
2594 LIMITED_METHOD_CONTRACT;
2597 FreeLibrary(m_hModule);
2603 #define UNKNOWN_SOURCE_FILE_PATH W("unknown")
2605 // ----------------------------------------------------------------------------
2606 // Manages generating all PDB data for an EE Module. Directly responsible for writing the
2607 // string table and file checksum subsections. One of these is instantiated per Module
2608 // found when using the ModuleIterator over the CORINFO_ASSEMBLY_HANDLE corresponding to
2609 // this invocation of NGEN createpdb.
2611 class NGenModulePdbWriter
2614 // Simple holder to coordinate the PDB calls to OpenModW and CloseMod on a given PDB
2619 ReleaseHolder<ISymNGenWriter2> m_pWriter;
2627 LIMITED_METHOD_CONTRACT;
2632 LIMITED_METHOD_CONTRACT;
2634 if ((m_pWriter != NULL) && (m_pMod != NULL))
2636 m_pWriter->CloseMod(m_pMod);
2640 HRESULT Open(ISymNGenWriter2 * pWriter, LPCWSTR wszModule, LPCWSTR wszObjFile)
2642 LIMITED_METHOD_CONTRACT;
2644 _ASSERTE(m_pWriter == NULL);
2646 m_pWriter = pWriter;
2647 m_pWriter->AddRef();
2649 _ASSERTE(m_pMod == NULL);
2651 HRESULT hr = m_pWriter->OpenModW(wszModule, wszObjFile, &m_pMod);
2661 LIMITED_METHOD_CONTRACT;
2663 _ASSERTE(m_pMod != NULL);
2669 // This holder ensures we delete a half-generated PDB file if we manage to create it
2670 // on disk, but fail at some point after it was created. When NGenModulePdbWriter is
2671 // destroyed, m_deletePDBFileHolder's destructor will delete the PDB file if there
2672 // was a prior error.
2674 //************* NOTE! *************
2676 // These members should appear FIRST so that they get destructed last. That way, if
2677 // we encounter an error generating the PDB file, we ensure that we release all PDB
2678 // interfaces and close the PDB file BEFORE this holder tries to *delete* the PDB
2679 // file. Also, keep these two in this relative order, so that m_deletePDBFileHolder
2680 // is destructed before m_wszPDBFilePath.
2681 WCHAR m_wszPDBFilePath[MAX_LONGPATH];
2682 DeleteFileHolder m_deletePDBFileHolder;
2684 // ************* NOTE! *************
2686 CreateNGenPdbWriter_t m_Create;
2687 LPCWSTR m_wszPdbPath;
2688 ReleaseHolder<ISymNGenWriter2> m_pWriter;
2690 DWORD m_dwExtraData;
2691 LPCWSTR m_wszManagedPDBSearchPath;
2693 // Currently The DiasymWriter does not use the correct PDB signature for NGEN PDBS unless
2694 // the NGEN DLL whose symbols are being generated end in .ni.dll. Thus we copy
2695 // to this name if it does not follow this covention (as is true with readyToRun
2696 // dlls). This variable remembers this temp file path so we can delete it after
2697 // Pdb generation. If DiaSymWriter is fixed, we can remove this.
2698 SString m_tempSourceDllName;
2700 // Interfaces for reading IL PDB info
2701 ReleaseHolder<ISymUnmanagedBinder> m_pBinder;
2702 ReleaseHolder<ISymUnmanagedReader> m_pReader;
2703 NewInterfaceArrayHolder<ISymUnmanagedDocument> m_rgpDocs; // All docs in the PDB Mod
2704 // I know m_ilPdbCount and m_finalPdbDocCount are confusing.Here is the reason :
2705 // For NGenMethodLinesPdbWriter::WriteDebugSILLinesSubsection, we won't write the path info.
2706 // In order to let WriteDebugSILLinesSubsection find "UNKNOWN_SOURCE_FILE_PATH" which does
2707 // not exist in m_rgpDocs, no matter if we have IL PDB or not, we let m_finalPdbDocCount
2708 // equal m_ilPdbDocCount + 1 and write the extra one path as "UNKNOWN_SOURCE_FILE_PATH"
2709 ULONG32 m_ilPdbDocCount;
2710 ULONG32 m_finalPdbDocCount;
2712 // Keeps track of source file names and how they map to offsets in the relevant PDB
2714 DocNameToOffsetMap m_docNameToOffsetMap;
2716 // Holds a PDB Mod *
2717 PDBModHolder m_pdbMod;
2719 // Buffer in which to store the entire string table (i.e., list of all source file
2720 // names). This buffer is held alive as long as m_docNameToOffsetMap is needed, as
2721 // the latter contains offsets into this buffer.
2722 NewArrayHolder<BYTE> m_rgbStringTableSubsection;
2724 HRESULT InitILPdbData();
2725 HRESULT WriteStringTable();
2726 HRESULT WriteFileChecksums();
2729 NGenModulePdbWriter(CreateNGenPdbWriter_t Create, LPCWSTR wszPdbPath, DWORD dwExtraData, ISymUnmanagedBinder * pBinder, Module * pModule, LPCWSTR wszManagedPDBSearchPath)
2731 m_wszPdbPath(wszPdbPath),
2734 m_dwExtraData(dwExtraData),
2735 m_wszManagedPDBSearchPath(wszManagedPDBSearchPath),
2738 m_finalPdbDocCount(1)
2740 LIMITED_METHOD_CONTRACT;
2742 if (m_pBinder != NULL)
2743 m_pBinder->AddRef();
2745 ZeroMemory(m_wszPDBFilePath, sizeof(m_wszPDBFilePath));
2748 ~NGenModulePdbWriter();
2750 HRESULT WritePDBData();
2752 HRESULT WriteMethodPDBData(PEImageLayout * pLoadedLayout, USHORT iCodeSection, BYTE *pCodeBase, MethodDesc * hotDesc, PCODE start, bool isILPDBProvided);
2755 // ----------------------------------------------------------------------------
2756 // Manages generating the lines subsection in the PDB data for a given managed method.
2757 // One of these is instantiated per managed method we find when iterating through all
2758 // methods in a Module.
2760 class NGenMethodLinesPdbWriter
2763 ISymNGenWriter2 * m_pWriter;
2765 ISymUnmanagedReader * m_pReader;
2766 MethodDesc * m_hotDesc;
2768 USHORT m_iCodeSection;
2769 TADDR m_addrCodeSection;
2770 const IJitManager::MethodRegionInfo * m_pMethodRegionInfo;
2771 EECodeInfo * m_pCodeInfo;
2772 DocNameToOffsetMap * m_pDocNameToOffsetMap;
2773 bool m_isILPDBProvided;
2775 // IL-to-native map from JIT manager
2776 ULONG32 m_cIlNativeMap;
2777 NewArrayHolder<ICorDebugInfo::OffsetMapping> m_rgIlNativeMap;
2779 // IL PDB info for this one method
2780 NewInterfaceArrayHolder<ISymUnmanagedDocument> m_rgpDocs; // Source files defining this method.
2781 NewArrayHolder<ULONG32> m_rgilOffsets; // Array of IL offsets for this method
2782 NewArrayHolder<ULONG32> m_rgnLineStarts; // Array of source lines for this method
2783 ULONG32 m_cSeqPoints; // Count of above two parallel arrays
2785 HRESULT WriteNativeILMapPDBData();
2786 LPBYTE InitDebugLinesHeaderSection(
2787 DEBUG_S_SUBSECTION_TYPE type,
2788 ULONG32 ulCodeStartOffset,
2791 CV_DebugSSubsectionHeader_t **ppSubSectHeader /*out*/,
2792 CV_DebugSLinesHeader_t ** ppLinesHeader /*out*/,
2793 LPBYTE * ppbLinesSubsectionCur /*out*/);
2795 HRESULT WriteDebugSLinesSubsection(
2796 ULONG32 ulCodeStartOffset,
2798 MapIndexPair * rgMapIndexPairs,
2799 ULONG32 cMapIndexPairs);
2801 HRESULT WriteDebugSILLinesSubsection(
2802 ULONG32 ulCodeStartOffset,
2804 ICorDebugInfo::OffsetMapping * rgILNativeMap,
2805 ULONG32 rgILNativeMapAdjustSize);
2807 BOOL FinalizeLinesFileBlock(
2808 CV_DebugSLinesFileBlockHeader_t * pLinesFileBlockHeader,
2809 CV_Line_t * pLineBlockStart,
2810 CV_Line_t * pLineBlockAfterEnd
2812 , BOOL ignorekUnmappedIPCheck = false
2817 NGenMethodLinesPdbWriter(
2818 ISymNGenWriter2 * pWriter,
2820 ISymUnmanagedReader * pReader,
2821 MethodDesc * hotDesc,
2823 USHORT iCodeSection,
2824 TADDR addrCodeSection,
2825 const IJitManager::MethodRegionInfo * pMethodRegionInfo,
2826 EECodeInfo * pCodeInfo,
2827 DocNameToOffsetMap * pDocNameToOffsetMap,
2828 bool isILPDBProvided)
2829 : m_pWriter(pWriter),
2834 m_iCodeSection(iCodeSection),
2835 m_addrCodeSection(addrCodeSection),
2836 m_pMethodRegionInfo(pMethodRegionInfo),
2837 m_pCodeInfo(pCodeInfo),
2838 m_pDocNameToOffsetMap(pDocNameToOffsetMap),
2839 m_isILPDBProvided(isILPDBProvided),
2843 LIMITED_METHOD_CONTRACT;
2846 HRESULT WritePDBData();
2849 // ----------------------------------------------------------------------------
2850 // NGenPdbWriter implementation
2854 //---------------------------------------------------------------------------------------
2856 // Coordinates calling all the other classes & methods to generate PDB info for the
2860 // pModule - EE Module to write PDB data for
2863 HRESULT NGenPdbWriter::WritePDBDataForModule(Module * pModule)
2865 STANDARD_VM_CONTRACT;
2866 NGenModulePdbWriter ngenModulePdbWriter(m_Create, m_wszPdbPath, m_dwExtraData, m_pBinder, pModule, m_wszManagedPDBSearchPath);
2867 return ngenModulePdbWriter.WritePDBData();
2871 // ----------------------------------------------------------------------------
2872 // NGenModulePdbWriter implementation
2875 //---------------------------------------------------------------------------------------
2877 // Writes out all source files into the string table subsection for the PDB Mod*
2878 // controlled by this NGenModulePdbWriter. Updates m_docNameToOffsetMap to add string
2879 // table offset for each source file as it gets added.
2881 HRESULT NGenModulePdbWriter::WriteStringTable()
2883 STANDARD_VM_CONTRACT;
2885 _ASSERTE(m_pWriter != NULL);
2888 UINT64 cbStringTableEstimate =
2890 sizeof(CV_DebugSSubsectionHeader_t) +
2891 m_finalPdbDocCount * (MAX_LONGPATH + 1);
2892 if (!FitsIn<ULONG32>(cbStringTableEstimate))
2894 return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
2897 m_rgbStringTableSubsection = new BYTE[ULONG32(cbStringTableEstimate)];
2898 LPBYTE pbStringTableSubsectionCur = m_rgbStringTableSubsection;
2900 // Subsection signature
2901 *((DWORD *) pbStringTableSubsectionCur) = CV_SIGNATURE_C13;
2902 pbStringTableSubsectionCur += sizeof(DWORD);
2904 // Subsection header
2905 CV_DebugSSubsectionHeader_t * pSubSectHeader = (CV_DebugSSubsectionHeader_t *) pbStringTableSubsectionCur;
2906 memset(pSubSectHeader, 0, sizeof(*pSubSectHeader));
2907 pSubSectHeader->type = DEBUG_S_STRINGTABLE;
2908 pbStringTableSubsectionCur += sizeof(*pSubSectHeader);
2909 // pSubSectHeader->cbLen counts the number of bytes that appear AFTER the subsection
2910 // header above (i.e., the size of the string table itself). We'll fill out
2911 // pSubSectHeader->cbLen below, once it's calculated
2913 LPBYTE pbStringTableStart = pbStringTableSubsectionCur;
2915 // The actual strings
2916 for (ULONG32 i = 0; i < m_finalPdbDocCount; i++)
2918 // For NGenMethodLinesPdbWriter::WriteDebugSILLinesSubsection, we won't write the path info.
2919 // In order to let WriteDebugSILLinesSubsection can find "UNKNOWN_SOURCE_FILE_PATH" which is
2920 // not existed in m_rgpDocs, no matter we have IL PDB or not, we let m_finalPdbDocCount equals to
2921 // m_ilPdbDocCount + 1 and write the extra one path as "UNKNOWN_SOURCE_FILE_PATH". That also explains
2922 // why we have a inconsistence between m_finalPdbDocCount and m_ilPdbDocCount.
2923 WCHAR wszURL[MAX_LONGPATH] = UNKNOWN_SOURCE_FILE_PATH;
2925 if (i < m_ilPdbDocCount)
2927 hr = m_rgpDocs[i]->GetURL(_countof(wszURL), &cchURL, wszURL);
2931 int cbWritten = WideCharToMultiByte(
2935 -1, // i.e., input is NULL-terminated
2936 (LPSTR) pbStringTableSubsectionCur, // output: UTF8 string starts here
2937 ULONG32(cbStringTableEstimate) -
2938 int(pbStringTableSubsectionCur - m_rgbStringTableSubsection), // Available space
2939 NULL, // lpDefaultChar
2940 NULL // lpUsedDefaultChar
2943 return HRESULT_FROM_WIN32(GetLastError());
2945 // Remember the string table offset for later
2946 m_docNameToOffsetMap.AddOrReplace(
2947 (LPCSTR) pbStringTableSubsectionCur,
2949 ULONG32(pbStringTableSubsectionCur - pbStringTableStart),
2952 pbStringTableSubsectionCur += cbWritten;
2953 if (pbStringTableSubsectionCur >= (m_rgbStringTableSubsection + cbStringTableEstimate))
2954 return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
2957 // Now that we know pSubSectHeader->cbLen, fill it in
2958 pSubSectHeader->cbLen = CV_off32_t(pbStringTableSubsectionCur - pbStringTableStart);
2960 // Subsection is now filled out, so use the PDB API to add it
2961 hr = m_pWriter->ModAddSymbols(
2962 m_pdbMod.GetModPtr(),
2963 m_rgbStringTableSubsection,
2964 int(pbStringTableSubsectionCur - m_rgbStringTableSubsection));
2971 //---------------------------------------------------------------------------------------
2973 // This takes care of actually loading the IL PDB itself, and initializing the
2974 // ISymUnmanaged* interfaces with module-level data from the IL PDB.
2976 HRESULT NGenModulePdbWriter::InitILPdbData()
2978 // Load the managed PDB
2980 ReleaseHolder<IUnknown> pUnk = NULL;
2981 HRESULT hr = m_pModule->GetReadablePublicMetaDataInterface(ofReadOnly, IID_IMetaDataImport, (LPVOID *) &pUnk);
2984 GetSvcLogger()->Printf(
2985 W("Unable to obtain metadata for '%s' Error: '0x%x'.\n"),
2986 LPCWSTR(m_pModule->GetFile()->GetILimage()->GetPath()),
2991 hr = m_pBinder->GetReaderForFile(
2993 m_pModule->GetFile()->GetILimage()->GetPath(),
2994 m_wszManagedPDBSearchPath,
2998 GetSvcLogger()->Printf(
2999 W("Unable to find managed PDB matching '%s'. Managed PDB search path: '%s'\n"),
3000 LPCWSTR(m_pModule->GetFile()->GetILimage()->GetPath()),
3001 (((m_wszManagedPDBSearchPath == NULL) || (*m_wszManagedPDBSearchPath == W('\0'))) ?
3002 W("(not specified)") :
3003 m_wszManagedPDBSearchPath));
3007 GetSvcLogger()->Log(W("Loaded managed PDB"));
3009 // Grab the full path of the managed PDB so we can log it
3010 WCHAR wszIlPdbPath[MAX_LONGPATH];
3011 ULONG32 cchIlPdbPath;
3012 hr = m_pReader->GetSymbolStoreFileName(
3013 _countof(wszIlPdbPath),
3018 GetSvcLogger()->Log(W("\n"));
3022 GetSvcLogger()->Printf(W(": '%s'\n"), wszIlPdbPath);
3025 // Read all source files names from the IL PDB
3027 hr = m_pReader->GetDocuments(
3028 0, // cDocsRequested
3035 m_rgpDocs = new ISymUnmanagedDocument * [cDocs];
3036 hr = m_pReader->GetDocuments(
3042 m_finalPdbDocCount = m_ilPdbDocCount + 1;
3043 // Commit m_rgpDocs to calling Release() on each ISymUnmanagedDocument* in the array
3044 m_rgpDocs.SetElementCount(m_ilPdbDocCount);
3049 NGenModulePdbWriter::~NGenModulePdbWriter()
3051 // Delete any temporary files we created.
3052 if (m_tempSourceDllName.GetCount() != 0)
3053 DeleteFileW(m_tempSourceDllName);
3054 m_tempSourceDllName.Clear();
3057 //---------------------------------------------------------------------------------------
3059 // This manages writing all Module-level data to the PDB, including public symbols,
3060 // string table, files checksum, section contribution table, and, indirectly, the lines
3063 HRESULT NGenModulePdbWriter::WritePDBData()
3065 STANDARD_VM_CONTRACT;
3067 _ASSERTE(m_pWriter == NULL);
3071 // This will try to open the managed PDB if lines info was requested. This is a
3072 // likely failure point, so intentionally do this before creating the NGEN PDB file
3074 bool isILPDBProvided = false;
3075 if ((m_dwExtraData & kPDBLines) != 0)
3077 hr = InitILPdbData();
3080 isILPDBProvided = true;
3083 // Create the PDB file we will write into.
3085 _ASSERTE(m_Create != NULL);
3086 _ASSERTE(m_pModule != NULL);
3088 PEImageLayout * pLoadedLayout = m_pModule->GetFile()->GetLoaded();
3090 // Currently DiaSymReader does not work properly generating NGEN PDBS unless
3091 // the DLL whose PDB is being generated ends in .ni.*. Unfortunately, readyToRun
3092 // images do not follow this convention and end up producing bad PDBS. To fix
3093 // this (without changing diasymreader.dll which ships indepdendently of .Net Core)
3094 // we copy the file to somethign with this convention before generating the PDB
3095 // and delete it when we are done.
3096 SString dllPath = pLoadedLayout->GetPath();
3097 if (!dllPath.EndsWithCaseInsensitive(W(".ni.dll")) && !dllPath.EndsWithCaseInsensitive(W(".ni.exe")))
3099 SString::Iterator fileNameStart = dllPath.End();
3100 dllPath.FindBack(fileNameStart, DIRECTORY_SEPARATOR_STR_W);
3102 SString::Iterator ext = dllPath.End();
3103 dllPath.FindBack(ext, '.');
3105 // m_tempSourceDllName = Convertion of INPUT.dll to INPUT.ni.dll where the PDB lives.
3106 m_tempSourceDllName = m_wszPdbPath;
3107 m_tempSourceDllName += SString(dllPath, fileNameStart, ext - fileNameStart);
3108 m_tempSourceDllName += W(".ni");
3109 m_tempSourceDllName += SString(dllPath, ext, dllPath.End() - ext);
3110 CopyFileW(dllPath, m_tempSourceDllName, false);
3111 dllPath = m_tempSourceDllName;
3114 ReleaseHolder<ISymNGenWriter> pWriter1;
3115 hr = m_Create(dllPath, m_wszPdbPath, &pWriter1);
3119 hr = pWriter1->QueryInterface(IID_ISymNGenWriter2, (LPVOID*) &m_pWriter);
3122 GetSvcLogger()->Printf(
3123 W("An incorrect version of diasymreader.dll was found. Please ensure that version 11 or greater of diasymreader.dll is on the path. You can typically find this DLL in the desktop .NET install directory for 4.5 or greater. Error='0x%x'\n"),
3128 // PDB file is now created. Get its path and initialize the holder so the PDB file
3129 // can be deleted if we don't make it successfully to the end
3131 hr = m_pWriter->QueryPDBNameExW(m_wszPDBFilePath, _countof(m_wszPDBFilePath));
3134 // A failure in QueryPDBNameExW above isn't fatal--it just means we can't
3135 // initialize m_deletePDBFileHolder, and thus may leave the PDB file on disk if
3136 // there's *another* error later on. And if we do hit another error, NGEN will
3137 // still return an error exit code, so the worst we'll have is a bogus PDB file
3138 // that no one should expect works anyway.
3139 m_deletePDBFileHolder.Assign(m_wszPDBFilePath);
3143 hr = m_pdbMod.Open(m_pWriter, pLoadedLayout->GetPath(), m_pModule->GetPath());
3147 hr = WriteStringTable();
3151 hr = WriteFileChecksums();
3156 COUNT_T sectionCount = pLoadedLayout->GetNumberOfSections();
3157 IMAGE_SECTION_HEADER *section = pLoadedLayout->FindFirstSection();
3158 COUNT_T sectionIndex = 0;
3159 USHORT iCodeSection = 0;
3160 BYTE *pCodeBase = NULL;
3161 while (sectionIndex < sectionCount)
3163 hr = m_pWriter->AddSection((USHORT)(sectionIndex + 1),
3166 section[sectionIndex].SizeOfRawData);
3170 if (strcmp((const char *)§ion[sectionIndex].Name[0], ".text") == 0) {
3171 _ASSERTE((iCodeSection == 0) && (pCodeBase == NULL));
3172 iCodeSection = (USHORT)(sectionIndex + 1);
3173 pCodeBase = (BYTE *)section[sectionIndex].VirtualAddress;
3176 // In order to support the DIA RVA-to-lines API against the PDB we're
3177 // generating, we need to update the section contribution table with each
3179 hr = m_pWriter->ModAddSecContribEx(
3180 m_pdbMod.GetModPtr(),
3181 (USHORT)(sectionIndex + 1),
3183 section[sectionIndex].SizeOfRawData,
3184 section[sectionIndex].Characteristics,
3194 _ASSERTE(iCodeSection != 0);
3195 _ASSERTE(pCodeBase != NULL);
3198 // To support lines info, we need a "dummy" section, indexed as 0, for use as a
3199 // sentinel when MSPDB sets up its section contribution table
3200 hr = m_pWriter->AddSection(0, // Dummy section 0
3208 #ifdef FEATURE_READYTORUN_COMPILER
3209 if (pLoadedLayout->HasReadyToRunHeader())
3211 ReadyToRunInfo::MethodIterator mi(m_pModule->GetReadyToRunInfo());
3214 MethodDesc *hotDesc = mi.GetMethodDesc();
3216 hr = WriteMethodPDBData(pLoadedLayout, iCodeSection, pCodeBase, hotDesc, mi.GetMethodStartAddress(), isILPDBProvided);
3222 #endif // FEATURE_READYTORUN_COMPILER
3224 MethodIterator mi(m_pModule);
3227 MethodDesc *hotDesc = mi.GetMethodDesc();
3228 hotDesc->CheckRestore();
3230 hr = WriteMethodPDBData(pLoadedLayout, iCodeSection, pCodeBase, hotDesc, mi.GetMethodStartAddress(), isILPDBProvided);
3236 // We made it successfully to the end, so don't delete the PDB file.
3237 m_deletePDBFileHolder.SuppressRelease();
3241 HRESULT NGenModulePdbWriter::WriteMethodPDBData(PEImageLayout * pLoadedLayout, USHORT iCodeSection, BYTE *pCodeBase, MethodDesc * hotDesc, PCODE start, bool isILPDBProvided)
3243 STANDARD_VM_CONTRACT;
3247 EECodeInfo codeInfo(start);
3248 _ASSERTE(codeInfo.IsValid());
3250 IJitManager::MethodRegionInfo methodRegionInfo;
3251 codeInfo.GetMethodRegionInfo(&methodRegionInfo);
3253 PCODE pHotCodeStart = methodRegionInfo.hotStartAddress;
3254 _ASSERTE(pHotCodeStart);
3256 PCODE pColdCodeStart = methodRegionInfo.coldStartAddress;
3257 SString mAssemblyName;
3258 mAssemblyName.SetUTF8(m_pModule->GetAssembly()->GetSimpleName());
3259 SString assemblyName;
3260 assemblyName.SetUTF8(hotDesc->GetAssembly()->GetSimpleName());
3261 SString methodToken;
3262 methodToken.Printf("%X", hotDesc->GetMemberDef());
3267 TypeString::AppendMethodInternal(
3270 TypeString::FormatNamespace | TypeString::FormatSignature);
3271 fullName.Append(W("$#"));
3272 if (!mAssemblyName.Equals(assemblyName))
3273 fullName.Append(assemblyName);
3274 fullName.Append(W("#"));
3275 fullName.Append(methodToken);
3276 BSTRHolder hotNameHolder(SysAllocString(fullName.GetUnicode()));
3277 hr = m_pWriter->AddSymbol(hotNameHolder,
3279 (pHotCodeStart - (TADDR)pLoadedLayout->GetBase() - (TADDR)pCodeBase));
3286 if (pColdCodeStart) {
3288 SString fullNameCold;
3289 fullNameCold.Append(W("[COLD] "));
3290 TypeString::AppendMethodInternal(
3293 TypeString::FormatNamespace | TypeString::FormatSignature);
3294 fullNameCold.Append(W("$#"));
3295 if (!mAssemblyName.Equals(assemblyName))
3296 fullNameCold.Append(assemblyName);
3297 fullNameCold.Append(W("#"));
3298 fullNameCold.Append(methodToken);
3300 BSTRHolder coldNameHolder(SysAllocString(fullNameCold.GetUnicode()));
3301 hr = m_pWriter->AddSymbol(coldNameHolder,
3303 (pColdCodeStart - (TADDR)pLoadedLayout->GetBase() - (TADDR)pCodeBase));
3311 // Offset / lines mapping
3312 // Skip functions that are too big for PDB lines format
3313 if (FitsIn<DWORD>(methodRegionInfo.hotSize) &&
3314 FitsIn<DWORD>(methodRegionInfo.coldSize))
3316 NGenMethodLinesPdbWriter methodLinesWriter(
3318 m_pdbMod.GetModPtr(),
3323 (TADDR)pLoadedLayout->GetBase() + (TADDR)pCodeBase,
3326 &m_docNameToOffsetMap,
3329 hr = methodLinesWriter.WritePDBData();
3337 // ----------------------------------------------------------------------------
3338 // Handles writing the file checksums subsection to the PDB
3340 HRESULT NGenModulePdbWriter::WriteFileChecksums()
3342 STANDARD_VM_CONTRACT;
3344 _ASSERTE(m_pWriter != NULL);
3346 // The file checksums subsection of the PDB (i.e., "DEBUG_S_FILECHKSMS"), is a blob
3347 // consisting of a few structs stacked one after the other:
3349 // * (1) DWORD = CV_SIGNATURE_C13 -- the usual subsection signature DWORD
3350 // * (2) CV_DebugSSubsectionHeader_t -- the usual subsection header, with type =
3351 // DEBUG_S_FILECHKSMS
3352 // * (3) Blob consisting of an array of checksum data -- the format of this piece is
3353 // not defined via structs (not sure why), but is defined in
3354 // vctools\PDB\doc\lines.docx
3358 // PDB format requires that the checksum size can always be expressed in a BYTE.
3359 const BYTE kcbEachChecksumEstimate = 0xFF;
3361 UINT64 cbChecksumSubsectionEstimate =
3363 sizeof(CV_DebugSSubsectionHeader_t) +
3364 m_finalPdbDocCount * kcbEachChecksumEstimate;
3365 if (!FitsIn<ULONG32>(cbChecksumSubsectionEstimate))
3367 return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
3370 NewArrayHolder<BYTE> rgbChksumSubsection(new BYTE[ULONG32(cbChecksumSubsectionEstimate)]);
3371 LPBYTE pbChksumSubsectionCur = rgbChksumSubsection;
3373 // (1) Subsection signature
3374 *((DWORD *) pbChksumSubsectionCur) = CV_SIGNATURE_C13;
3375 pbChksumSubsectionCur += sizeof(DWORD);
3377 // (2) Subsection header
3378 CV_DebugSSubsectionHeader_t * pSubSectHeader = (CV_DebugSSubsectionHeader_t *) pbChksumSubsectionCur;
3379 memset(pSubSectHeader, 0, sizeof(*pSubSectHeader));
3380 pSubSectHeader->type = DEBUG_S_FILECHKSMS;
3381 pbChksumSubsectionCur += sizeof(*pSubSectHeader);
3382 // pSubSectHeader->cblen to be filled in later once we know the size
3384 LPBYTE pbChksumDataStart = pbChksumSubsectionCur;
3386 // (3) Iterate through source files, steal their checksum info from the IL PDB, and
3387 // write it into the NGEN PDB.
3388 for (ULONG32 i = 0; i < m_finalPdbDocCount; i++)
3390 WCHAR wszURL[MAX_LONGPATH] = UNKNOWN_SOURCE_FILE_PATH;
3391 char szURL[MAX_LONGPATH];
3395 bool isKnownSourcePath = i < m_ilPdbDocCount;
3396 if (isKnownSourcePath)
3398 // For NGenMethodLinesPdbWriter::WriteDebugSILLinesSubsection, we won't write the path info.
3399 // In order to let WriteDebugSILLinesSubsection can find "UNKNOWN_SOURCE_FILE_PATH" which is
3400 // not existed in m_rgpDocs, no matter we have IL PDB or not, we let m_finalPdbDocCount equals to
3401 // m_ilPdbDocCount + 1 and write the extra one path as "UNKNOWN_SOURCE_FILE_PATH". That also explains
3402 // why we have a inconsistence between m_finalPdbDocCount and m_ilPdbDocCount.
3403 hr = m_rgpDocs[i]->GetURL(_countof(wszURL), &cchURL, wszURL);
3408 int cbWritten = WideCharToMultiByte(
3412 -1, // i.e., input is NULL-terminated
3413 szURL, // output: UTF8 string starts here
3414 _countof(szURL), // Available space
3415 NULL, // lpDefaultChar
3416 NULL // lpUsedDefaultChar
3419 return HRESULT_FROM_WIN32(GetLastError());
3421 // find offset into string table and add to blob; meanwhile update hash to
3422 // remember the offset into the cksum table
3423 const KeyValuePair<LPCSTR,DocNameOffsets> * pMapEntry =
3424 m_docNameToOffsetMap.LookupPtr(szURL);
3425 if (pMapEntry == NULL)
3427 // Should never happen, as it implies we found a source file that was never
3428 // written to the string table
3429 return E_UNEXPECTED;
3431 DocNameOffsets docNameOffsets(pMapEntry->Value());
3432 docNameOffsets.m_dwChksumTableOffset = ULONG32(pbChksumSubsectionCur - pbChksumDataStart);
3434 // Update the map with the new docNameOffsets that contains the cksum table
3435 // offset as well. Note that we must ensure the key (LPCSTR) remains the same
3436 // (thus we explicitly ask for the Key()). This class guarantees that string
3437 // pointer (which comes from the string table buffer field) will remain allocated
3438 // as long as the map is.
3439 m_docNameToOffsetMap.AddOrReplace(pMapEntry->Key(), docNameOffsets);
3440 * (ULONG32 *) pbChksumSubsectionCur = docNameOffsets.m_dwStrTableOffset;
3441 pbChksumSubsectionCur += sizeof(ULONG32);
3443 // Checksum algorithm and bytes
3445 BYTE rgbChecksum[kcbEachChecksumEstimate];
3446 ULONG32 cbChecksum = 0;
3447 BYTE bChecksumAlgorithmType = CHKSUM_TYPE_NONE;
3448 if (isKnownSourcePath)
3450 GUID guidChecksumAlgorithm;
3451 hr = m_rgpDocs[i]->GetCheckSumAlgorithmId(&guidChecksumAlgorithm);
3454 // If we got the checksum algorithm, we can write it all out to the buffer.
3455 // Else, we'll just omit the checksum info
3456 if (memcmp(&guidChecksumAlgorithm, &CorSym_SourceHash_MD5, sizeof(GUID)) == 0)
3457 bChecksumAlgorithmType = CHKSUM_TYPE_MD5;
3458 else if (memcmp(&guidChecksumAlgorithm, &CorSym_SourceHash_SHA1, sizeof(GUID)) == 0)
3459 bChecksumAlgorithmType = CHKSUM_TYPE_SHA1;
3463 if (bChecksumAlgorithmType != CHKSUM_TYPE_NONE)
3465 hr = m_rgpDocs[i]->GetCheckSum(sizeof(rgbChecksum), &cbChecksum, rgbChecksum);
3466 if (FAILED(hr) || !FitsIn<BYTE>(cbChecksum))
3468 // Should never happen, but just in case checksum data is invalid, just put
3469 // no checksum into the NGEN PDB
3470 bChecksumAlgorithmType = CHKSUM_TYPE_NONE;
3475 // checksum length & algorithm
3476 *pbChksumSubsectionCur = (BYTE) cbChecksum;
3477 pbChksumSubsectionCur++;
3478 *pbChksumSubsectionCur = bChecksumAlgorithmType;
3479 pbChksumSubsectionCur++;
3481 // checksum data bytes
3482 memcpy(pbChksumSubsectionCur, rgbChecksum, cbChecksum);
3483 pbChksumSubsectionCur += cbChecksum;
3485 // Must align to the next 4-byte boundary
3486 LPBYTE pbChksumSubsectionCurAligned = (LPBYTE) ALIGN_UP(pbChksumSubsectionCur, 4);
3487 memset(pbChksumSubsectionCur, 0, pbChksumSubsectionCurAligned-pbChksumSubsectionCur);
3488 pbChksumSubsectionCur = pbChksumSubsectionCurAligned;
3491 // Now that we know pSubSectHeader->cbLen, fill it in
3492 pSubSectHeader->cbLen = CV_off32_t(pbChksumSubsectionCur - pbChksumDataStart);
3494 // Subsection is now filled out, so add it
3495 hr = m_pWriter->ModAddSymbols(
3496 m_pdbMod.GetModPtr(),
3497 rgbChksumSubsection,
3498 int(pbChksumSubsectionCur - rgbChksumSubsection));
3505 // ----------------------------------------------------------------------------
3506 // NGenMethodLinesPdbWriter implementation
3509 //---------------------------------------------------------------------------------------
3511 // Manages the writing of all lines-file subsections requred for a given method. if a
3512 // method is hot/cold split, this will write two line-file subsections to the PDB--one
3513 // for the hot region, and one for the cold.
3516 HRESULT NGenMethodLinesPdbWriter::WritePDBData()
3518 STANDARD_VM_CONTRACT;
3520 if (m_hotDesc->IsNoMetadata())
3522 // IL stubs will not have data in the IL PDB, so just skip them.
3527 // First, we'll need to merge the IL-to-native map from the JIT manager with the
3528 // IL-to-source map from the IL PDB. This merging is done into a single piece that
3529 // includes all regions of the code when it's split
3532 // Grab the IL-to-native map from the JIT manager
3533 DebugInfoRequest debugInfoRequest;
3534 debugInfoRequest.InitFromStartingAddr(m_hotDesc, m_start);
3535 BOOL fSuccess = m_pCodeInfo->GetJitManager()->GetBoundariesAndVars(
3537 SimpleNew, NULL, // Allocator
3543 // Shouldn't happen, but just skip this method if it does
3547 if (FAILED(hr = WriteNativeILMapPDBData()))
3552 if (!m_isILPDBProvided)
3557 // We will traverse this IL-to-native map (from the JIT) in parallel with the
3558 // source-to-IL map provided by the IL PDB (below). Both need to be sorted by IL so
3559 // we can easily find matching entries in the two maps
3560 QuickSortILNativeMapByIL sorterByIl(m_rgIlNativeMap, m_cIlNativeMap);
3563 // Now grab IL-to-source map from the IL PDBs (just known as "sequence points"
3564 // according to the IL PDB API)
3566 ReleaseHolder<ISymUnmanagedMethod> pMethod;
3567 hr = m_pReader->GetMethod(
3568 m_hotDesc->GetMemberDef(),
3572 // Ignore any methods not included in the IL PDB. Although we've already
3573 // excluded LCG & IL stubs from methods we're considering, there can still be
3574 // methods in the NGEN module that are not in the IL PDB (e.g., implicit ctors).
3578 ULONG32 cSeqPointsExpected;
3579 hr = pMethod->GetSequencePointCount(&cSeqPointsExpected);
3582 // Should never happen, but we can just skip this function if the IL PDB can't
3583 // find sequence point info
3587 ULONG32 cSeqPointsReturned;
3588 m_rgilOffsets = new ULONG32[cSeqPointsExpected];
3589 m_rgpDocs = new ISymUnmanagedDocument * [cSeqPointsExpected];
3590 m_rgnLineStarts = new ULONG32[cSeqPointsExpected];
3592 // This is guaranteed to return the sequence points sorted in order of the IL
3593 // offsets (m_rgilOffsets)
3594 hr = pMethod->GetSequencePoints(
3596 &cSeqPointsReturned,
3600 NULL, // ColumnStarts not needed
3601 NULL, // LineEnds not needed
3602 NULL); // ColumnEnds not needed
3605 // Shouldn't happen, but just skip this method if it does
3608 // Commit m_rgpDocs to calling Release() on all ISymUnmanagedDocument* returned into
3610 m_rgpDocs.SetElementCount(cSeqPointsReturned);
3612 // Now merge the two maps together into an array of MapIndexPair structures. Traverse
3613 // both maps in parallel (both ordered by IL offset), looking for IL offset matches.
3614 // Range matching: If an entry in the IL-to-native map has no matching entry in the
3615 // IL PDB, then seek up in the IL PDB to the previous sequence point and merge to
3616 // that (assuming that previous sequence point from the IL PDB did not already have
3617 // an exact match to some other entry in the IL-to-native map).
3618 ULONG32 cMapIndexPairsMax = m_cIlNativeMap;
3619 NewArrayHolder<MapIndexPair> rgMapIndexPairs(new MapIndexPair [cMapIndexPairsMax]);
3620 ULONG32 iSeqPoints = 0;
3622 // Keep track (via iSeqPointLastUnmatched) of the most recent entry in the IL PDB
3623 // that we passed over because it had no matching entry in the IL-to-native map. We
3624 // may use this to do a range-match if necessary. We'll set iSeqPointLastUnmatched to
3625 // the currently interated IL PDB entry after our cursor in the il-to-native map
3626 // passed it by, but only if fCurSeqPointMatched is FALSE
3627 ULONG32 iSeqPointLastUnmatched = (ULONG32) -1;
3628 BOOL fCurSeqPointMatched = FALSE;
3630 ULONG32 iIlNativeMap = 0;
3631 ULONG32 iMapIndexPairs = 0;
3633 // Traverse IL PDB entries and IL-to-native map entries (both sorted by IL) in
3636 // * Record matching indices in our output map, rgMapIndexPairs, indexed by
3639 // * We will have at most m_cIlNativeMap entries in rgMapIndexPairs by the time
3640 // we're done. (Each il-to-native map entry will be considered for inclusion
3641 // in this output. Those il-to-native map entries with a match in the il PDB
3642 // will be included, the rest skipped.)
3644 // * iSeqPointLastUnmatched != -1 iff it equals a prior entry in the IL PDB that
3645 // we skipped over because it could not be exactly matched to an entry in the
3646 // il-to-native map. In such a case, it will be considered for a
3647 // range-match to the next il-to-native map entry
3648 while (iIlNativeMap < m_cIlNativeMap)
3650 _ASSERTE (iMapIndexPairs < cMapIndexPairsMax);
3652 // IP addresses that map to "special" places (prolog, epilog, or
3653 // other hidden code), will just map to 0xFeeFee, as per convention
3654 if ((m_rgIlNativeMap[iIlNativeMap].ilOffset == NO_MAPPING) ||
3655 (m_rgIlNativeMap[iIlNativeMap].ilOffset == PROLOG) ||
3656 (m_rgIlNativeMap[iIlNativeMap].ilOffset == EPILOG))
3658 rgMapIndexPairs[iMapIndexPairs].m_iIlNativeMap = iIlNativeMap;
3659 rgMapIndexPairs[iMapIndexPairs].m_iSeqPoints = kUnmappedIP;
3662 // If we were remembering a prior unmatched entry in the IL PDB, reset it
3663 iSeqPointLastUnmatched = (ULONG32) -1;
3665 // Advance il-native map, NOT il-source map
3670 // Cases below actually look at the IL PDB sequence point, so ensure it's still
3671 // in range; otherwise, we're done.
3672 if (iSeqPoints >= cSeqPointsReturned)
3675 if (m_rgIlNativeMap[iIlNativeMap].ilOffset < m_rgilOffsets[iSeqPoints])
3677 // Our cursor over the ilnative map is behind the sourceil
3680 if (iSeqPointLastUnmatched != (ULONG32) -1)
3682 // Range matching: This ilnative entry is behind our cursor in the
3683 // sourceil map, but this ilnative entry is also ahead of the previous
3684 // (unmatched) entry in the sourceil map. So this is a case where the JIT
3685 // generated sequence points that surround, without matching, that
3686 // previous entry in the sourceil map. So match to that previous
3687 // (unmatched) entry in the sourceil map.
3688 _ASSERTE(m_rgilOffsets[iSeqPointLastUnmatched] < m_rgIlNativeMap[iIlNativeMap].ilOffset);
3689 rgMapIndexPairs[iMapIndexPairs].m_iIlNativeMap = iIlNativeMap;
3690 rgMapIndexPairs[iMapIndexPairs].m_iSeqPoints = iSeqPointLastUnmatched;
3693 // Reset our memory of the last unmatched entry in the IL PDB
3694 iSeqPointLastUnmatched = (ULONG32) -1;
3696 else if (iMapIndexPairs > 0)
3698 DWORD lastMatchedilNativeIndex = rgMapIndexPairs[iMapIndexPairs - 1].m_iIlNativeMap;
3699 if (m_rgIlNativeMap[iIlNativeMap].ilOffset == m_rgIlNativeMap[lastMatchedilNativeIndex].ilOffset &&
3700 m_rgIlNativeMap[iIlNativeMap].nativeOffset < m_rgIlNativeMap[lastMatchedilNativeIndex].nativeOffset)
3702 rgMapIndexPairs[iMapIndexPairs - 1].m_iIlNativeMap = iIlNativeMap;
3706 // Go to next ilnative map entry
3711 if (m_rgilOffsets[iSeqPoints] < m_rgIlNativeMap[iIlNativeMap].ilOffset)
3713 // Our cursor over the ilnative map is ahead of the sourceil
3714 // map, so go to next sourceil map entry. Remember that we're passing over
3715 // this entry in the sourceil map, in case we choose to match to it later.
3716 if (!fCurSeqPointMatched)
3718 iSeqPointLastUnmatched = iSeqPoints;
3721 fCurSeqPointMatched = FALSE;
3726 _ASSERTE(m_rgilOffsets[iSeqPoints] == m_rgIlNativeMap[iIlNativeMap].ilOffset);
3727 rgMapIndexPairs[iMapIndexPairs].m_iIlNativeMap = iIlNativeMap;
3728 rgMapIndexPairs[iMapIndexPairs].m_iSeqPoints = iSeqPoints;
3730 // If we were remembering a prior unmatched entry in the IL PDB, reset it
3731 iSeqPointLastUnmatched = (ULONG32) -1;
3733 // Advance il-native map, do not advance il-source map in case the next il-native
3734 // entry matches this current il-source map entry, but remember that this current
3735 // il-source map entry has found an exact match
3738 fCurSeqPointMatched = TRUE;
3741 ULONG32 cMapIndexPairs = iMapIndexPairs;
3743 // PDB format requires the lines array to be sorted by IP offset
3744 QuickSortMapIndexPairsByNativeOffset sorterByIp(rgMapIndexPairs, cMapIndexPairs, m_rgIlNativeMap, m_cIlNativeMap);
3748 // Now that the maps are merged and sorted, determine whether there's a hot/cold
3749 // split, where that split is, and then call WriteLinesSubsection to write out each
3750 // region into its own lines-file subsection
3753 // Find the point where the code got split
3754 ULONG32 iMapIndexPairsFirstEntryInColdSection = cMapIndexPairs;
3755 for (iMapIndexPairs = 0; iMapIndexPairs < cMapIndexPairs; iMapIndexPairs++)
3757 DWORD dwNativeOffset = m_rgIlNativeMap[rgMapIndexPairs[iMapIndexPairs].m_iIlNativeMap].nativeOffset;
3758 if (dwNativeOffset >= m_pMethodRegionInfo->hotSize)
3760 iMapIndexPairsFirstEntryInColdSection = iMapIndexPairs;
3765 // Adjust the cold offsets (if any) to be relative to the cold start
3766 for (iMapIndexPairs = iMapIndexPairsFirstEntryInColdSection; iMapIndexPairs < cMapIndexPairs; iMapIndexPairs++)
3768 DWORD dwNativeOffset = m_rgIlNativeMap[rgMapIndexPairs[iMapIndexPairs].m_iIlNativeMap].nativeOffset;
3769 _ASSERTE (dwNativeOffset >= m_pMethodRegionInfo->hotSize);
3771 // Adjust offset so it's relative to the cold region start
3772 dwNativeOffset -= DWORD(m_pMethodRegionInfo->hotSize);
3773 _ASSERTE(dwNativeOffset < m_pMethodRegionInfo->coldSize);
3774 m_rgIlNativeMap[rgMapIndexPairs[iMapIndexPairs].m_iIlNativeMap].nativeOffset = dwNativeOffset;
3777 // Write out the hot region into its own lines-file subsection
3778 hr = WriteDebugSLinesSubsection(
3779 ULONG32(m_pMethodRegionInfo->hotStartAddress - m_addrCodeSection),
3780 ULONG32(m_pMethodRegionInfo->hotSize),
3782 iMapIndexPairsFirstEntryInColdSection);
3786 // If there was a hot/cold split, write a separate lines-file subsection for the cold
3788 if (iMapIndexPairsFirstEntryInColdSection < cMapIndexPairs)
3790 hr = WriteDebugSLinesSubsection(
3791 ULONG32(m_pMethodRegionInfo->coldStartAddress - m_addrCodeSection),
3792 ULONG32(m_pMethodRegionInfo->coldSize),
3793 &rgMapIndexPairs[iMapIndexPairsFirstEntryInColdSection],
3794 cMapIndexPairs - iMapIndexPairsFirstEntryInColdSection);
3802 //---------------------------------------------------------------------------------------
3804 // Manages the writing of all native-IL subsections requred for a given method. Almost do
3805 // the same thing as NGenMethodLinesPdbWriter::WritePDBData. But we will write the native-IL
3809 HRESULT NGenMethodLinesPdbWriter::WriteNativeILMapPDBData()
3811 STANDARD_VM_CONTRACT;
3815 QuickSortILNativeMapByNativeOffset sorterByNativeOffset(m_rgIlNativeMap, m_cIlNativeMap);
3816 sorterByNativeOffset.Sort();
3818 ULONG32 iIlNativeMap = 0;
3819 ULONG32 ilNativeMapFirstEntryInColdeSection = m_cIlNativeMap;
3820 for (iIlNativeMap = 0; iIlNativeMap < m_cIlNativeMap; iIlNativeMap++)
3822 if (m_rgIlNativeMap[iIlNativeMap].nativeOffset >= m_pMethodRegionInfo->hotSize)
3824 ilNativeMapFirstEntryInColdeSection = iIlNativeMap;
3829 NewArrayHolder<ICorDebugInfo::OffsetMapping> coldRgIlNativeMap(new ICorDebugInfo::OffsetMapping[m_cIlNativeMap - ilNativeMapFirstEntryInColdeSection]);
3830 // Adjust the cold offsets (if any) to be relative to the cold start
3831 for (iIlNativeMap = ilNativeMapFirstEntryInColdeSection; iIlNativeMap < m_cIlNativeMap; iIlNativeMap++)
3833 DWORD dwNativeOffset = m_rgIlNativeMap[iIlNativeMap].nativeOffset;
3834 _ASSERTE(dwNativeOffset >= m_pMethodRegionInfo->hotSize);
3836 // Adjust offset so it's relative to the cold region start
3837 dwNativeOffset -= DWORD(m_pMethodRegionInfo->hotSize);
3838 _ASSERTE(dwNativeOffset < m_pMethodRegionInfo->coldSize);
3839 coldRgIlNativeMap[iIlNativeMap - ilNativeMapFirstEntryInColdeSection].ilOffset = m_rgIlNativeMap[iIlNativeMap].ilOffset;
3840 coldRgIlNativeMap[iIlNativeMap - ilNativeMapFirstEntryInColdeSection].nativeOffset = dwNativeOffset;
3841 coldRgIlNativeMap[iIlNativeMap - ilNativeMapFirstEntryInColdeSection].source = m_rgIlNativeMap[iIlNativeMap].source;
3844 // Write out the hot region into its own lines-file subsection
3845 hr = WriteDebugSILLinesSubsection(
3846 ULONG32(m_pMethodRegionInfo->hotStartAddress - m_addrCodeSection),
3847 ULONG32(m_pMethodRegionInfo->hotSize),
3849 ilNativeMapFirstEntryInColdeSection);
3853 // If there was a hot/cold split, write a separate lines-file subsection for the cold
3855 if (ilNativeMapFirstEntryInColdeSection < m_cIlNativeMap)
3857 hr = WriteDebugSILLinesSubsection(
3858 ULONG32(m_pMethodRegionInfo->coldStartAddress - m_addrCodeSection),
3859 ULONG32(m_pMethodRegionInfo->coldSize),
3861 m_cIlNativeMap - ilNativeMapFirstEntryInColdeSection);
3870 //---------------------------------------------------------------------------------------
3872 // Helper called by NGenMethodLinesPdbWriter::WriteDebugSLinesSubsection and
3873 // NGenMethodLinesPdbWriter::WriteDebugSILLinesSubsection to initial the DEBUG_S*_LINE
3874 // subsection headers.
3877 // * ulCodeStartOffset - Offset relative to the code section, or where this region
3879 // * type - the subsection's type
3880 // * lineSize - how many lines mapping the subsection will have.
3881 // * cbCode - Size in bytes of this region of code
3882 // * ppSubSectHeader - output value which returns the intialed CV_DebugSLinesHeader_t struct pointer.
3883 // * ppLinesHeader - output value which returns the initialed CV_DebugSLinesHeader_t struct pointer.
3884 // * ppbLinesSubsectionCur - output value which points to the address right after the DebugSLinesHeader
3887 // * Pointer which points the staring address of the SubSection.
3890 LPBYTE NGenMethodLinesPdbWriter::InitDebugLinesHeaderSection(
3891 DEBUG_S_SUBSECTION_TYPE type,
3892 ULONG32 ulCodeStartOffset,
3895 CV_DebugSSubsectionHeader_t **ppSubSectHeader /*out*/,
3896 CV_DebugSLinesHeader_t ** ppLinesHeader /*out*/,
3897 LPBYTE * ppbLinesSubsectionCur /*out*/)
3899 STANDARD_VM_CONTRACT;
3901 UINT64 cbLinesSubsectionEstimate =
3903 sizeof(CV_DebugSSubsectionHeader_t) +
3904 sizeof(CV_DebugSLinesHeader_t) +
3905 // Worst case: assume each sequence point will require its own
3906 // CV_DebugSLinesFileBlockHeader_t
3907 (lineSize * (sizeof(CV_DebugSLinesFileBlockHeader_t) + sizeof(CV_Line_t)));
3908 if (!FitsIn<ULONG32>(cbLinesSubsectionEstimate))
3913 LPBYTE rgbLinesSubsection = new BYTE[ULONG32(cbLinesSubsectionEstimate)];
3914 LPBYTE pbLinesSubsectionCur = rgbLinesSubsection;
3916 // * (1) DWORD = CV_SIGNATURE_C13 -- the usual subsection signature DWORD
3917 *((DWORD *)pbLinesSubsectionCur) = CV_SIGNATURE_C13;
3918 pbLinesSubsectionCur += sizeof(DWORD);
3920 // * (2) CV_DebugSSubsectionHeader_t
3921 CV_DebugSSubsectionHeader_t * pSubSectHeader = (CV_DebugSSubsectionHeader_t *)pbLinesSubsectionCur;
3922 memset(pSubSectHeader, 0, sizeof(*pSubSectHeader));
3923 pSubSectHeader->type = type;
3924 *ppSubSectHeader = pSubSectHeader;
3925 // pSubSectHeader->cblen to be filled in later once we know the size
3926 pbLinesSubsectionCur += sizeof(*pSubSectHeader);
3928 // * (3) CV_DebugSLinesHeader_t
3929 CV_DebugSLinesHeader_t * pLinesHeader = (CV_DebugSLinesHeader_t *)pbLinesSubsectionCur;
3930 memset(pLinesHeader, 0, sizeof(*pLinesHeader));
3931 pLinesHeader->offCon = ulCodeStartOffset;
3932 pLinesHeader->segCon = m_iCodeSection;
3933 pLinesHeader->flags = 0; // 0 means line info, but not column info, is included
3934 pLinesHeader->cbCon = cbCode;
3935 *ppLinesHeader = pLinesHeader;
3936 pbLinesSubsectionCur += sizeof(*pLinesHeader);
3937 *ppbLinesSubsectionCur = pbLinesSubsectionCur;
3938 return rgbLinesSubsection;
3941 //---------------------------------------------------------------------------------------
3943 // Helper called by NGenMethodLinesPdbWriter::WritePDBData to do the actual PDB writing of a single
3944 // lines-subsection. This is called once for the hot region, and once for the cold
3945 // region, of a given method that has been split. That means you get two
3946 // lines-subsections for split methods.
3949 // * ulCodeStartOffset - Offset relative to the code section, or where this region
3951 // * cbCode - Size in bytes of this region of code
3952 // * rgMapIndexPairs - Array of indices forming the merged data from the JIT
3953 // Manager's IL-to-native map and the IL PDB's IL-to-source map. It is assumed
3954 // that this array has indices sorted such that the native offsets increase
3955 // * cMapIndexPairs - Size in entries of above array.
3958 // rgMapIndexPairs must be sorted in order of nativeOffset, i.e.,
3959 // m_rgIlNativeMap[rgMapIndexPairs[i].m_iIlNativeMap].nativeOffset increases with i.
3962 HRESULT NGenMethodLinesPdbWriter::WriteDebugSLinesSubsection(
3963 ULONG32 ulCodeStartOffset,
3965 MapIndexPair * rgMapIndexPairs,
3966 ULONG32 cMapIndexPairs)
3968 STANDARD_VM_CONTRACT;
3970 // The lines subsection of the PDB (i.e., "DEBUG_S_LINES"), is a blob consisting of a
3971 // few structs stacked one after the other:
3973 // * (1) DWORD = CV_SIGNATURE_C13 -- the usual subsection signature DWORD
3974 // * (2) CV_DebugSSubsectionHeader_t -- the usual subsection header, with type =
3976 // * (3) CV_DebugSLinesHeader_t -- a single header for the entire subsection. Its
3977 // purpose is to specify the native function being described, and to specify the
3978 // size of the variable-sized "blocks" that follow
3979 // * (4) CV_DebugSLinesFileBlockHeader_t -- For each block, you get one of these. A
3980 // block is defined by a set of sequence points that map to the same source
3981 // file. While iterating through the offsets, we need to define new blocks
3982 // whenever the source file changes. In C#, this typically only happens when
3983 // you advance to (or away from) an unmapped IP (0xFeeFee).
3984 // * (5) CV_Line_t (Line array entries) -- For each block, you get several line
3985 // array entries, one entry for the beginning of each sequence point.
3990 CV_DebugSSubsectionHeader_t * pSubSectHeader = NULL;
3991 CV_DebugSLinesHeader_t * pLinesHeader = NULL;
3992 CV_DebugSLinesFileBlockHeader_t * LinesFileBlockHeader = NULL;
3994 // the InitDebugLinesHeaderSection will help us taking care of
3995 // * (1) DWORD = CV_SIGNATURE_C13
3996 // * (2) CV_DebugSSubsectionHeader_t
3997 // * (3) CV_DebugSLinesHeader_t
3998 LPBYTE pbLinesSubsectionCur;
3999 LPBYTE prgbLinesSubsection = InitDebugLinesHeaderSection(
4006 &pbLinesSubsectionCur);
4008 if (pbLinesSubsectionCur == NULL)
4010 return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
4013 NewArrayHolder<BYTE> rgbLinesSubsection(prgbLinesSubsection);
4015 // The loop below takes care of
4016 // * (4) CV_DebugSLinesFileBlockHeader_t
4017 // * (5) CV_Line_t (Line array entries)
4019 BOOL fAtLeastOneBlockWritten = FALSE;
4020 CV_DebugSLinesFileBlockHeader_t * pLinesFileBlockHeader = NULL;
4021 CV_Line_t * pLineCur = NULL;
4022 CV_Line_t * pLinePrev = NULL;
4023 CV_Line_t * pLineBlockStart = NULL;
4024 BOOL fBeginNewBlock = TRUE;
4025 ULONG32 iSeqPointsPrev = (ULONG32) -1;
4026 DWORD dwNativeOffsetPrev = (DWORD) -1;
4027 DWORD ilOffsetPrev = (DWORD) -1;
4028 WCHAR wszURLPrev[MAX_LONGPATH];
4029 memset(&wszURLPrev, 0, sizeof(wszURLPrev));
4030 LPBYTE pbEnd = NULL;
4032 for (ULONG32 iMapIndexPairs=0; iMapIndexPairs < cMapIndexPairs; iMapIndexPairs++)
4034 ULONG32 iSeqPoints = rgMapIndexPairs[iMapIndexPairs].m_iSeqPoints;
4035 ULONG32 iIlNativeMap = rgMapIndexPairs[iMapIndexPairs].m_iIlNativeMap;
4037 // Sometimes the JIT manager will give us duplicate IPs in the IL-to-native
4038 // offset mapping. PDB format frowns on that. Since rgMapIndexPairs is being
4039 // iterated in native offset order, it's easy to find these dupes right now, and
4040 // skip all but the first map containing a given IP offset.
4041 if (pLinePrev != NULL && m_rgIlNativeMap[iIlNativeMap].nativeOffset == pLinePrev->offset)
4043 if (ilOffsetPrev == kUnmappedIP)
4045 // if the previous IL offset is kUnmappedIP, then we should rewrite it.
4046 pLineCur = pLinePrev;
4048 else if (iSeqPoints != kUnmappedIP &&
4049 m_rgilOffsets[iSeqPoints] < ilOffsetPrev)
4051 pLineCur = pLinePrev;
4055 // Found a native offset dupe, ignore the current map entry
4060 if ((iSeqPoints != kUnmappedIP) && (iSeqPoints != iSeqPointsPrev))
4062 // This is the first iteration where we're looking at this iSeqPoints. So
4063 // check whether the document name has changed on us. If it has, that means
4064 // we need to start a new block.
4065 WCHAR wszURL[MAX_LONGPATH];
4067 hr = m_rgpDocs[iSeqPoints]->GetURL(_countof(wszURL), &cchURL, wszURL);
4070 // Skip function if IL PDB has data missing
4074 // wszURL is the best we have for a unique identifier of documents. See
4075 // whether the previous document's URL is different
4076 if (_wcsicmp(wszURL, wszURLPrev) != 0)
4078 // New document. Update wszURLPrev, and remember that we need to start a
4080 if (wcscpy_s(wszURLPrev, _countof(wszURLPrev), wszURL) != 0)
4084 fBeginNewBlock = TRUE;
4087 iSeqPointsPrev = iSeqPoints;
4091 // We've determined that we need to start a new block. So perform fixups
4092 // against the previous block (if any) first
4093 if (FinalizeLinesFileBlock(pLinesFileBlockHeader, pLineBlockStart, pLineCur))
4095 fAtLeastOneBlockWritten = TRUE;
4097 else if (pLinesFileBlockHeader != NULL)
4099 // Previous block had no usable data. So rewind back to the previous
4100 // block header, and we'll start there with the next block
4101 pbLinesSubsectionCur = LPBYTE(pLinesFileBlockHeader);
4102 pLineCur = (CV_Line_t *) pbLinesSubsectionCur;
4105 // Now get the info we'll need for the next block
4106 char szURL[MAX_LONGPATH];
4107 int cbWritten = WideCharToMultiByte(
4111 -1, // i.e., input is NULL-terminated
4112 szURL, // output: UTF8 string starts here
4113 _countof(szURL), // Available space
4114 NULL, // lpDefaultChar
4115 NULL // lpUsedDefaultChar
4120 DocNameOffsets docNameOffsets;
4121 BOOL fExists = m_pDocNameToOffsetMap->Lookup(szURL, &docNameOffsets);
4124 _ASSERTE(docNameOffsets.m_dwChksumTableOffset != (ULONG32) -1);
4128 // We may get back an invalid document in the 0xFeeFee case (i.e., a
4129 // sequence point that intentionally doesn't map back to a publicly
4130 // available source code line). In that case, we'll use the bogus cksum
4131 // offset of -1 for now, and verify we're in the 0xFeeFee case later on
4132 // (see code:NGenMethodLinesPdbWriter::FinalizeLinesFileBlock).
4133 _ASSERTE(szURL[0] == '\0');
4134 _ASSERTE(docNameOffsets.m_dwChksumTableOffset == (ULONG32) -1);
4138 // * (4) CV_DebugSLinesFileBlockHeader_t
4139 if (pLineCur == NULL)
4141 // First lines file block, so begin the block header immediately after the
4142 // subsection headers
4143 pLinesFileBlockHeader = (CV_DebugSLinesFileBlockHeader_t *) pbLinesSubsectionCur;
4147 // We've had blocks before this one, so add this block at our current
4148 // location in the blob
4149 pLinesFileBlockHeader = (CV_DebugSLinesFileBlockHeader_t *) pLineCur;
4152 // PDB structure sizes guarantee this is the case, though their docs are
4153 // explicit that each lines-file block header must be 4-byte aligned.
4154 _ASSERTE(IS_ALIGNED(pLinesFileBlockHeader, 4));
4156 memset(pLinesFileBlockHeader, 0, sizeof(*pLinesFileBlockHeader));
4157 pLinesFileBlockHeader->offFile = docNameOffsets.m_dwChksumTableOffset;
4158 // pLinesFileBlockHeader->nLines to be filled in when block is complete
4159 // pLinesFileBlockHeader->cbBlock to be filled in when block is complete
4161 pLineCur = (CV_Line_t *) (pLinesFileBlockHeader + 1);
4162 pLineBlockStart = pLineCur;
4163 fBeginNewBlock = FALSE;
4167 pLineCur->offset = m_rgIlNativeMap[iIlNativeMap].nativeOffset;
4168 pLineCur->linenumStart =
4169 (iSeqPoints == kUnmappedIP) ?
4171 m_rgnLineStarts[iSeqPoints];
4172 pLineCur->deltaLineEnd = 0;
4173 pLineCur->fStatement = 1;
4174 ilOffsetPrev = (iSeqPoints == kUnmappedIP) ? kUnmappedIP : m_rgilOffsets[iSeqPoints];
4175 pLinePrev = pLineCur;
4177 } // for (ULONG32 iMapIndexPairs=0; iMapIndexPairs < cMapIndexPairs; iMapIndexPairs++)
4179 if (pLineCur == NULL)
4181 // There were no lines data for this function, so don't write anything
4185 // Perform fixups against the last block we wrote
4186 if (FinalizeLinesFileBlock(pLinesFileBlockHeader, pLineBlockStart, pLineCur))
4187 fAtLeastOneBlockWritten = TRUE;
4189 if (!fAtLeastOneBlockWritten)
4191 // There were no valid blocks to write for this function, so don't bother
4192 // calling PDB writing API. No problem.
4196 // Now that we know pSubSectHeader->cbLen, fill it in
4197 pSubSectHeader->cbLen = CV_off32_t(LPBYTE(pLineCur) - LPBYTE(pLinesHeader));
4199 // Subsection is now filled out, so add it.
4200 hr = m_pWriter->ModAddSymbols(
4204 // The size we pass here is the size of the entire byte array that we pass in.
4205 int(LPBYTE(pLineCur) - rgbLinesSubsection));
4213 //---------------------------------------------------------------------------------------
4215 // Helper called by NGenMethodLinesPdbWriter::WriteNativeILMapPDBData to do the actual PDB writing of a single
4216 // lines-subsection. This is called once for the hot region, and once for the cold
4217 // region, of a given method that has been split. That means you get two
4218 // lines-subsections for split methods.
4221 // * ulCodeStartOffset - Offset relative to the code section, or where this region
4223 // * cbCode - Size in bytes of this region of code
4224 // * rgIlNativeMap - IL to Native map array.
4225 // * rgILNativeMapAdjustSize - the number of elements we need to read in rgILNativeMap.
4228 HRESULT NGenMethodLinesPdbWriter::WriteDebugSILLinesSubsection(
4229 ULONG32 ulCodeStartOffset,
4231 ICorDebugInfo::OffsetMapping * rgIlNativeMap,
4232 ULONG32 rgILNativeMapAdjustSize)
4234 STANDARD_VM_CONTRACT;
4236 // The lines subsection of the PDB (i.e., "DEBUG_S_IL_LINES"), is a blob consisting of a
4237 // few structs stacked one after the other:
4239 // * (1) DWORD = CV_SIGNATURE_C13 -- the usual subsection signature DWORD
4240 // * (2) CV_DebugSSubsectionHeader_t -- the usual subsection header, with type =
4242 // * (3) CV_DebugSLinesHeader_t -- a single header for the entire subsection. Its
4243 // purpose is to specify the native function being described, and to specify the
4244 // size of the variable-sized "blocks" that follow
4245 // * (4) CV_DebugSLinesFileBlockHeader_t -- For each block, you get one of these. A
4246 // block is defined by a set of sequence points that map to the same source
4247 // file. While iterating through the offsets, we need to define new blocks
4248 // whenever the source file changes. In C#, this typically only happens when
4249 // you advance to (or away from) an unmapped IP (0xFeeFee).
4250 // * (5) CV_Line_t (Line array entries) -- For each block, you get several line
4251 // array entries, one entry for the beginning of each sequence point.
4255 CV_DebugSSubsectionHeader_t * pSubSectHeader = NULL;
4256 CV_DebugSLinesHeader_t * pLinesHeader = NULL;
4257 CV_DebugSLinesFileBlockHeader_t * pLinesFileBlockHeader = NULL;
4259 // the InitDebugLinesHeaderSection will help us taking care of
4260 // * (1) DWORD = CV_SIGNATURE_C13
4261 // * (2) CV_DebugSSubsectionHeader_t
4262 // * (3) CV_DebugSLinesHeader_t
4263 LPBYTE pbLinesSubsectionCur;
4264 LPBYTE prgbLinesSubsection = InitDebugLinesHeaderSection(
4268 rgILNativeMapAdjustSize,
4271 &pbLinesSubsectionCur);
4273 if (prgbLinesSubsection == NULL)
4275 return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
4278 NewArrayHolder<BYTE> rgbLinesSubsection(prgbLinesSubsection);
4280 // The loop below takes care of
4281 // * (4) CV_DebugSLinesFileBlockHeader_t
4282 // * (5) CV_Line_t (Line array entries)
4284 CV_Line_t * pLineCur = NULL;
4285 CV_Line_t * pLineBlockStart = NULL;
4286 BOOL fBeginNewBlock = TRUE;
4287 LPBYTE pbEnd = NULL;
4289 pLinesFileBlockHeader = (CV_DebugSLinesFileBlockHeader_t *)pbLinesSubsectionCur;
4290 // PDB structure sizes guarantee this is the case, though their docs are
4291 // explicit that each lines-file block header must be 4-byte aligned.
4292 _ASSERTE(IS_ALIGNED(pLinesFileBlockHeader, 4));
4294 memset(pLinesFileBlockHeader, 0, sizeof(*pLinesFileBlockHeader));
4295 char szURL[MAX_PATH];
4296 int cbWritten = WideCharToMultiByte(
4299 UNKNOWN_SOURCE_FILE_PATH,
4300 -1, // i.e., input is NULL-terminated
4301 szURL, // output: UTF8 string starts here
4302 _countof(szURL), // Available space
4303 NULL, // lpDefaultChar
4304 NULL // lpUsedDefaultChar
4306 _ASSERTE(cbWritten > 0);
4307 DocNameOffsets docNameOffsets;
4308 m_pDocNameToOffsetMap->Lookup(szURL, &docNameOffsets);
4309 pLinesFileBlockHeader->offFile = docNameOffsets.m_dwChksumTableOffset;
4310 // pLinesFileBlockHeader->nLines to be filled in when block is complete
4311 // pLinesFileBlockHeader->cbBlock to be filled in when block is complete
4313 pLineCur = (CV_Line_t *)(pLinesFileBlockHeader + 1);
4314 pLineBlockStart = pLineCur;
4315 CV_Line_t * pLinePrev = NULL;
4317 for (ULONG32 iINativeMap = 0;iINativeMap < rgILNativeMapAdjustSize; iINativeMap++)
4319 if ((rgIlNativeMap[iINativeMap].ilOffset == NO_MAPPING) ||
4320 (rgIlNativeMap[iINativeMap].ilOffset == PROLOG) ||
4321 (rgIlNativeMap[iINativeMap].ilOffset == EPILOG))
4323 rgIlNativeMap[iINativeMap].ilOffset = kUnmappedIP;
4326 // Sometimes the JIT manager will give us duplicate native offset in the IL-to-native
4327 // offset mapping. PDB format frowns on that. Since rgMapIndexPairs is being
4328 // iterated in native offset order, it's easy to find these dupes right now, and
4329 // skip all but the first map containing a given IP offset.
4330 if (pLinePrev != NULL &&
4331 rgIlNativeMap[iINativeMap].nativeOffset == pLinePrev->offset)
4333 if (pLinePrev->linenumStart == kUnmappedIP)
4335 // if the previous IL offset is kUnmappedIP, then we should rewrite it.
4336 pLineCur = pLinePrev;
4338 else if (rgIlNativeMap[iINativeMap].ilOffset != kUnmappedIP &&
4339 rgIlNativeMap[iINativeMap].ilOffset < pLinePrev->linenumStart)
4341 pLineCur = pLinePrev;
4345 // Found a native offset dupe, ignore the current map entry
4350 pLineCur->linenumStart = rgIlNativeMap[iINativeMap].ilOffset;
4352 pLineCur->offset = rgIlNativeMap[iINativeMap].nativeOffset;
4353 pLineCur->fStatement = 1;
4354 pLineCur->deltaLineEnd = 0;
4355 pLinePrev = pLineCur;
4359 if (pLineCur == NULL)
4361 // There were no lines data for this function, so don't write anything
4365 if (!FinalizeLinesFileBlock(pLinesFileBlockHeader, pLineBlockStart, pLineCur
4374 // Now that we know pSubSectHeader->cbLen, fill it in
4375 pSubSectHeader->cbLen = CV_off32_t(LPBYTE(pLineCur) - LPBYTE(pLinesHeader));
4377 // Subsection is now filled out, so add it.
4378 hr = m_pWriter->ModAddSymbols(
4382 // The size we pass here is the size of the entire byte array that we pass in.
4383 long(LPBYTE(pLineCur) - rgbLinesSubsection));
4391 //---------------------------------------------------------------------------------------
4393 // Performs final fixups on the last lines-file block we completed, specifically writing
4394 // in the size of the block, now that it's known. Also responsible for determining
4395 // whether there is even any data to write in the first place.
4398 // * pLinesFileBlockHeader - lines-file block header to write to
4399 // * pLineBlockStart - First CV_Line_t * of this block
4400 // * pLineBlockAfterEnd - Last CV_Line_t * of this block plus 1
4403 // * TRUE: lines-file block was nonempty, and is now finalized
4404 // * FALSE: lines-file block was empty, and caller should toss it out.
4407 BOOL NGenMethodLinesPdbWriter::FinalizeLinesFileBlock(
4408 CV_DebugSLinesFileBlockHeader_t * pLinesFileBlockHeader,
4409 CV_Line_t * pLineBlockStart,
4410 CV_Line_t * pLineBlockAfterEnd
4412 , BOOL ignorekUnmappedIPCheck
4416 LIMITED_METHOD_CONTRACT;
4418 if (pLinesFileBlockHeader == NULL)
4420 // If a given function has no sequence points at all, pLinesFileBlockHeader can
4421 // be NULL. No problem
4425 if (pLineBlockStart == pLineBlockAfterEnd)
4427 // If we start a lines file block and then realize that there are no entries
4428 // (i.e., no valid sequence points to map), then we end up with an empty block.
4429 // No problem, just skip the block.
4433 _ASSERTE(pLineBlockStart != NULL);
4434 _ASSERTE(pLineBlockAfterEnd != NULL);
4435 _ASSERTE(pLineBlockAfterEnd > pLineBlockStart);
4437 if (pLinesFileBlockHeader->offFile == (ULONG32) -1)
4439 // The file offset we set for this block is invalid. This should be due to the
4440 // 0xFeeFee case (i.e., sequence points that intentionally don't map back to a
4441 // publicly available source code line). Fix up the offset to be valid (point it
4442 // at the first file), but the offset will generally be ignored by the PDB
4446 if (!ignorekUnmappedIPCheck)
4448 for (CV_Line_t * pLineCur = pLineBlockStart; pLineCur < pLineBlockAfterEnd; pLineCur++)
4450 _ASSERTE(pLineCur->linenumStart == kUnmappedIP);
4455 pLinesFileBlockHeader->offFile = 0;
4458 // Now that we know the size of the block, finish filling out the lines file block
4460 pLinesFileBlockHeader->nLines = CV_off32_t(pLineBlockAfterEnd - pLineBlockStart);
4461 pLinesFileBlockHeader->cbBlock = pLinesFileBlockHeader->nLines * sizeof(CV_Line_t);
4465 #endif // NO_NGENPDB
4466 #if defined(FEATURE_PERFMAP) || !defined(NO_NGENPDB)
4467 HRESULT __stdcall CreatePdb(CORINFO_ASSEMBLY_HANDLE hAssembly, BSTR pNativeImagePath, BSTR pPdbPath, BOOL pdbLines, BSTR pManagedPdbSearchPath, LPCWSTR pDiasymreaderPath)
4469 STANDARD_VM_CONTRACT;
4471 Assembly *pAssembly = reinterpret_cast<Assembly *>(hAssembly);
4472 _ASSERTE(pAssembly);
4473 _ASSERTE(pNativeImagePath);
4476 #if !defined(NO_NGENPDB)
4477 NGenPdbWriter pdbWriter(
4480 pdbLines ? kPDBLines : 0,
4481 pManagedPdbSearchPath);
4482 IfFailThrow(pdbWriter.Load(pDiasymreaderPath));
4483 #elif defined(FEATURE_PERFMAP)
4484 NativeImagePerfMap perfMap(pAssembly, pPdbPath);
4487 ModuleIterator moduleIterator = pAssembly->IterateModules();
4488 Module *pModule = NULL;
4489 BOOL fAtLeastOneNativeModuleFound = FALSE;
4491 while (moduleIterator.Next())
4493 pModule = moduleIterator.GetModule();
4495 if (pModule->HasNativeImage() || pModule->IsReadyToRun())
4497 #if !defined(NO_NGENPDB)
4498 IfFailThrow(pdbWriter.WritePDBDataForModule(pModule));
4499 #elif defined(FEATURE_PERFMAP)
4500 perfMap.LogDataForModule(pModule);
4502 fAtLeastOneNativeModuleFound = TRUE;
4506 if (!fAtLeastOneNativeModuleFound)
4508 GetSvcLogger()->Printf(
4509 W("Loaded image '%s' (for input file '%s') is not a native image.\n"),
4510 pAssembly->GetManifestFile()->GetPath().GetUnicode(),
4512 return CORDBG_E_NO_IMAGE_AVAILABLE;
4515 GetSvcLogger()->Printf(
4516 #if !defined(NO_NGENPDB)
4517 W("Successfully generated PDB for native assembly '%s'.\n"),
4518 #elif defined(FEATURE_PERFMAP)
4519 W("Successfully generated perfmap for native assembly '%s'.\n"),
4526 HRESULT __stdcall CreatePdb(CORINFO_ASSEMBLY_HANDLE hAssembly, BSTR pNativeImagePath, BSTR pPdbPath, BOOL pdbLines, BSTR pManagedPdbSearchPath, LPCWSTR pDiasymreaderPath)
4530 #endif // defined(FEATURE_PERFMAP) || !defined(NO_NGENPDB)
4532 // End of PDB writing code
4533 // ----------------------------------------------------------------------------
4536 BOOL CEEPreloader::CanPrerestoreEmbedClassHandle(CORINFO_CLASS_HANDLE handle)
4538 STANDARD_VM_CONTRACT;
4540 if (IsReadyToRunCompilation())
4543 TypeHandle th(handle);
4545 return m_image->CanPrerestoreEagerBindToTypeHandle(th, NULL);
4548 BOOL CEEPreloader::CanPrerestoreEmbedMethodHandle(CORINFO_METHOD_HANDLE handle)
4550 STANDARD_VM_CONTRACT;
4552 if (IsReadyToRunCompilation())
4555 MethodDesc *pMD = (MethodDesc*) handle;
4557 return m_image->CanPrerestoreEagerBindToMethodDesc(pMD, NULL);
4560 ICorCompilePreloader * CEECompileInfo::PreloadModule(CORINFO_MODULE_HANDLE module,
4561 ICorCompileDataStore *pData,
4562 CorProfileData *profileData)
4564 STANDARD_VM_CONTRACT;
4566 NewHolder<CEEPreloader> pPreloader(new CEEPreloader((Module *) module, pData));
4568 COOPERATIVE_TRANSITION_BEGIN();
4570 if (PartialNGenStressPercentage() == 0)
4572 pPreloader->Preload(profileData);
4575 COOPERATIVE_TRANSITION_END();
4577 return pPreloader.Extract();
4580 void CEECompileInfo::SetAssemblyHardBindList(
4581 __in_ecount( cHardBindList )
4582 LPWSTR *pHardBindList,
4583 DWORD cHardBindList)
4585 STANDARD_VM_CONTRACT;
4589 HRESULT CEECompileInfo::SetVerboseLevel(
4590 IN VerboseLevel level)
4592 LIMITED_METHOD_CONTRACT;
4594 g_CorCompileVerboseLevel = level;
4601 CEEPreloader::CEEPreloader(Module *pModule,
4602 ICorCompileDataStore *pData)
4605 m_image = new DataImage(pModule, this);
4607 CONSISTENCY_CHECK(pModule == GetAppDomain()->ToCompilationDomain()->GetTargetModule());
4609 GetAppDomain()->ToCompilationDomain()->SetTargetImage(m_image, this);
4611 m_methodCompileLimit = pModule->GetMDImport()->GetCountWithTokenKind(mdtMethodDef) * 10;
4613 #ifdef FEATURE_FULL_NGEN
4614 m_fSpeculativeTriage = FALSE;
4615 m_fDictionariesPopulated = FALSE;
4619 CEEPreloader::~CEEPreloader()
4621 WRAPPER_NO_CONTRACT;
4625 void CEEPreloader::Preload(CorProfileData * profileData)
4627 STANDARD_VM_CONTRACT;
4629 bool doNothingNgen = false;
4631 static ConfigDWORD fDoNothingNGen;
4632 doNothingNgen = !!fDoNothingNGen.val(CLRConfig::INTERNAL_ZapDoNothing);
4637 m_image->GetModule()->SetProfileData(profileData);
4638 m_image->GetModule()->ExpandAll(m_image);
4641 // Triage all items created by initial expansion.
4642 // We will try to accept all items created by initial expansion.
4647 // ICorCompilerPreloader
4650 DWORD CEEPreloader::MapMethodEntryPoint(CORINFO_METHOD_HANDLE handle)
4652 STANDARD_VM_CONTRACT;
4654 MethodDesc *pMD = GetMethod(handle);
4655 Precode * pPrecode = pMD->GetSavedPrecode(m_image);
4657 return m_image->GetRVA(pPrecode);
4660 DWORD CEEPreloader::MapClassHandle(CORINFO_CLASS_HANDLE handle)
4662 STANDARD_VM_CONTRACT;
4664 TypeHandle th = TypeHandle::FromPtr(handle);
4665 if (th.IsTypeDesc())
4666 return m_image->GetRVA(th.AsTypeDesc()) | 2;
4668 return m_image->GetRVA(th.AsMethodTable());
4671 DWORD CEEPreloader::MapMethodHandle(CORINFO_METHOD_HANDLE handle)
4673 STANDARD_VM_CONTRACT;
4675 return m_image->GetRVA(handle);
4678 DWORD CEEPreloader::MapFieldHandle(CORINFO_FIELD_HANDLE handle)
4680 STANDARD_VM_CONTRACT;
4682 return m_image->GetRVA(handle);
4685 DWORD CEEPreloader::MapAddressOfPInvokeFixup(CORINFO_METHOD_HANDLE handle)
4687 STANDARD_VM_CONTRACT;
4689 MethodDesc *pMD = GetMethod(handle);
4691 _ASSERTE(pMD->IsNDirect());
4692 NDirectWriteableData * pMDWriteableData = ((NDirectMethodDesc *)pMD)->GetWriteableData();
4694 return m_image->GetRVA(pMDWriteableData) + offsetof(NDirectWriteableData, m_pNDirectTarget);
4697 DWORD CEEPreloader::MapGenericHandle(CORINFO_GENERIC_HANDLE handle)
4699 STANDARD_VM_CONTRACT;
4701 return m_image->GetRVA(handle);
4704 DWORD CEEPreloader::MapModuleIDHandle(CORINFO_MODULE_HANDLE handle)
4706 STANDARD_VM_CONTRACT;
4708 return m_image->GetRVA(handle) + (DWORD)Module::GetOffsetOfModuleID();
4711 CORINFO_METHOD_HANDLE CEEPreloader::NextUncompiledMethod()
4713 STANDARD_VM_CONTRACT;
4715 // If we have run out of methods to compile, ensure that we have code for all methods
4716 // that we are about to save.
4717 if (m_uncompiledMethods.GetCount() == 0)
4719 #ifdef FEATURE_FULL_NGEN
4720 if (!m_fSpeculativeTriage)
4722 // We take one shot at smarter elimination of speculative instantiations
4723 // that are guaranteed to be found in other modules
4724 TriageSpeculativeInstantiations();
4725 m_fSpeculativeTriage = TRUE;
4729 if (m_uncompiledMethods.GetCount() == 0)
4731 #ifdef FEATURE_FULL_NGEN
4732 if (!m_fDictionariesPopulated)
4734 // Prepopulate dictionaries. Only the first population is done in expansive way.
4735 m_image->GetModule()->PrepopulateDictionaries(m_image, FALSE);
4736 m_fDictionariesPopulated = TRUE;
4741 // The subsequent populations are done in non-expansive way (won't load new types)
4742 m_image->GetModule()->PrepopulateDictionaries(m_image, TRUE);
4745 // Make sure that we have generated code for all instantiations that we are going to save
4746 // The new items that we encounter here were most likely side effects of verification or failed inlining,
4747 // so do not try to save them eagerly.
4748 while (TriageForZap(FALSE)) {
4749 // Loop as long as new types are added
4754 // Take next uncompiled method
4755 COUNT_T count = m_uncompiledMethods.GetCount();
4759 MethodDesc * pMD = m_uncompiledMethods[count - 1];
4760 m_uncompiledMethods.SetCount(count - 1);
4763 if (LoggingOn(LF_ZAP, LL_INFO10000))
4765 StackSString methodString;
4766 TypeString::AppendMethodDebug(methodString, pMD);
4768 LOG((LF_ZAP, LL_INFO10000, "CEEPreloader::NextUncompiledMethod: %S\n", methodString.GetUnicode()));
4772 return (CORINFO_METHOD_HANDLE) pMD;
4775 void CEEPreloader::AddMethodToTransitiveClosureOfInstantiations(CORINFO_METHOD_HANDLE handle)
4777 STANDARD_VM_CONTRACT;
4779 TriageMethodForZap(GetMethod(handle), TRUE);
4782 BOOL CEEPreloader::IsMethodInTransitiveClosureOfInstantiations(CORINFO_METHOD_HANDLE handle)
4784 STANDARD_VM_CONTRACT;
4786 MethodDesc *pMD = GetMethod(handle);
4788 return (m_acceptedMethods.Lookup(pMD) != NULL) && (m_rejectedMethods.Lookup(pMD) == NULL);
4791 BOOL CEEPreloader::IsTypeInTransitiveClosureOfInstantiations(CORINFO_CLASS_HANDLE handle)
4793 STANDARD_VM_CONTRACT;
4795 TypeHandle th = (TypeHandle) handle;
4797 return (m_acceptedTypes.Lookup(th) != NULL) && (m_rejectedTypes.Lookup(th) == NULL);
4800 void CEEPreloader::MethodReferencedByCompiledCode(CORINFO_METHOD_HANDLE handle)
4802 STANDARD_VM_CONTRACT;
4804 #ifndef FEATURE_FULL_NGEN // Unreferenced methods
4806 // Keep track of methods that are actually referenced by the code. We use this information
4807 // to avoid generating code for unreferenced methods not visible outside the assembly.
4808 // These methods are very unlikely to be ever used at runtime because of they only ever be
4809 // called via private reflection.
4811 MethodDesc *pMD = GetMethod(handle);
4813 const CompileMethodEntry * pEntry = m_compileMethodsHash.LookupPtr(pMD);
4816 if (pEntry->fReferenced)
4818 const_cast<CompileMethodEntry *>(pEntry)->fReferenced = true;
4820 if (pEntry->fScheduled)
4822 AppendUncompiledMethod(pMD);
4826 CompileMethodEntry entry;
4828 entry.fReferenced = true;
4829 entry.fScheduled = false;
4830 m_compileMethodsHash.Add(entry);
4833 if (pMD->IsWrapperStub())
4834 MethodReferencedByCompiledCode((CORINFO_METHOD_HANDLE)pMD->GetWrappedMethodDesc());
4835 #endif // FEATURE_FULL_NGEN
4838 BOOL CEEPreloader::IsUncompiledMethod(CORINFO_METHOD_HANDLE handle)
4840 STANDARD_VM_CONTRACT;
4842 MethodDesc *pMD = GetMethod(handle);
4844 #ifndef FEATURE_FULL_NGEN // Unreferenced methods
4845 const CompileMethodEntry * pEntry = m_compileMethodsHash.LookupPtr(pMD);
4846 return (pEntry != NULL) && (pEntry->fScheduled || !pEntry->fReferenced);
4848 return m_compileMethodsHash.LookupPtr(pMD) != NULL;
4852 static bool IsTypeAccessibleOutsideItsAssembly(TypeHandle th)
4854 STANDARD_VM_CONTRACT;
4856 if (th.IsTypeDesc())
4858 if (th.AsTypeDesc()->HasTypeParam())
4859 return IsTypeAccessibleOutsideItsAssembly(th.AsTypeDesc()->GetTypeParam());
4864 MethodTable * pMT = th.AsMethodTable();
4866 if (pMT == g_pCanonMethodTableClass)
4869 switch (pMT->GetClass()->GetProtection())
4873 case tdNestedPublic:
4874 case tdNestedFamily:
4875 case tdNestedFamORAssem:
4877 MethodTable * pMTEnclosing = pMT->LoadEnclosingMethodTable();
4878 if (pMTEnclosing == NULL)
4880 if (!IsTypeAccessibleOutsideItsAssembly(pMTEnclosing))
4889 if (pMT->HasInstantiation())
4891 Instantiation instantiation = pMT->GetInstantiation();
4892 for (DWORD i = 0; i < instantiation.GetNumArgs(); i++)
4894 if (!IsTypeAccessibleOutsideItsAssembly(instantiation[i]))
4902 static bool IsMethodAccessibleOutsideItsAssembly(MethodDesc * pMD)
4904 STANDARD_VM_CONTRACT;
4906 // Note that this ignores friend access.
4908 switch (pMD->GetAttrs() & mdMemberAccessMask)
4919 if (!IsTypeAccessibleOutsideItsAssembly(pMD->GetMethodTable()))
4922 if (pMD->HasMethodInstantiation())
4924 Instantiation instantiation = pMD->GetMethodInstantiation();
4925 for (DWORD i = 0; i < instantiation.GetNumArgs(); i++)
4927 if (!IsTypeAccessibleOutsideItsAssembly(instantiation[i]))
4935 static bool IsMethodCallableOutsideItsAssembly(MethodDesc * pMD)
4937 STANDARD_VM_CONTRACT;
4939 // Virtual methods can be called via interfaces, etc. We would need to do
4940 // more analysis to trim them. For now, assume that they can be referenced outside this assembly.
4941 if (pMD->IsVirtual())
4944 // Class constructors are often used with reflection. Always generate code for them.
4945 if (pMD->IsClassConstructorOrCtor())
4948 if (IsMethodAccessibleOutsideItsAssembly(pMD))
4954 BOOL IsGenericTooDeeplyNested(TypeHandle t);
4955 void CEEPreloader::AddToUncompiledMethods(MethodDesc *pMD, BOOL fForStubs)
4957 STANDARD_VM_CONTRACT;
4959 // TriageTypeForZap() and TriageMethodForZap() should ensure this.
4960 _ASSERTE(m_image->GetModule() == pMD->GetLoaderModule());
4967 if (!pMD->MayHaveNativeCode() && !pMD->IsWrapperStub())
4971 // If it's already been compiled, don't add it to the set of uncompiled methods
4972 if (m_image->GetCodeAddress(pMD) != NULL)
4975 // If it's already in the queue to be compiled don't add it again
4976 const CompileMethodEntry * pEntry = m_compileMethodsHash.LookupPtr(pMD);
4978 #ifndef FEATURE_FULL_NGEN // Unreferenced methods
4981 if (pEntry->fScheduled)
4984 if (!pEntry->fReferenced)
4987 const_cast<CompileMethodEntry *>(pEntry)->fScheduled = true;
4991 // The unreferenced methods optimization works for generic methods and methods on generic types only.
4992 // Non-generic methods take different path.
4994 // It unclear whether it is worth it to enable it for non-generic methods too. The benefit
4995 // for non-generic methods is small, and the non-generic methods are more likely to be called
4996 // via private reflection.
4998 bool fSchedule = fForStubs || IsMethodCallableOutsideItsAssembly(pMD);
5000 CompileMethodEntry entry;
5002 entry.fScheduled = fSchedule;
5003 entry.fReferenced = false;
5004 m_compileMethodsHash.Add(entry);
5009 #else // // FEATURE_FULL_NGEN
5010 // Schedule the method for compilation
5013 CompileMethodEntry entry;
5015 m_compileMethodsHash.Add(entry);
5016 #endif // FEATURE_FULL_NGEN
5018 if (pMD->HasMethodInstantiation())
5020 Instantiation instantiation = pMD->GetMethodInstantiation();
5021 for (DWORD i = 0; i < instantiation.GetNumArgs(); i++)
5023 if (IsGenericTooDeeplyNested(instantiation[i]))
5028 // Add it to the set of uncompiled methods
5029 AppendUncompiledMethod(pMD);
5033 // Used to validate instantiations produced by the production rules before we actually try to instantiate them.
5035 static BOOL CanSatisfyConstraints(Instantiation typicalInst, Instantiation candidateInst)
5037 STANDARD_VM_CONTRACT;
5039 // The dependency must be of the form C<T> --> D<T>
5040 _ASSERTE(typicalInst.GetNumArgs() == candidateInst.GetNumArgs());
5041 if (typicalInst.GetNumArgs() != candidateInst.GetNumArgs())
5044 SigTypeContext typeContext(candidateInst, Instantiation());
5046 for (DWORD i = 0; i < candidateInst.GetNumArgs(); i++)
5048 TypeHandle thArg = candidateInst[i];
5050 // If this is "__Canon" and we are code sharing then we can't rule out that some
5051 // compatible instantiation may meet the constraints
5052 if (thArg == TypeHandle(g_pCanonMethodTableClass))
5055 // Otherwise we approximate, and just assume that we have "parametric" constraints
5056 // of the form "T : IComparable<T>" rather than "odd" constraints such as "T : IComparable<string>".
5057 // That is, we assume checking the constraint at the canonical type is sufficient
5058 // to tell us if the constraint holds for all compatible types.
5060 // For example of where this does not hold, consider if
5062 // class D<T> where T : IComparable<T>
5063 // struct Struct<T> : IComparable<string>
5064 // Assume we generate C<Struct<object>>. Now the constraint
5065 // Struct<object> : IComparable<object>
5066 // does not hold, so we do not generate the instantiation, even though strictly speaking
5067 // the compatible instantiation C<Struct<string>> will satisfy the constraint
5068 // Struct<string> : IComparable<string>
5070 TypeVarTypeDesc* tyvar = typicalInst[i].AsGenericVariable();
5072 tyvar->LoadConstraints();
5074 if (!tyvar->SatisfiesConstraints(&typeContext,thArg)) {
5077 // In case we want to know which illegal instantiations we ngen'ed
5078 StackSString candidateInstName;
5079 StackScratchBuffer buffer;
5080 thArg.GetName(candidateInstName);
5082 _snprintf_s(output, _countof(output), _TRUNCATE, "Generics TypeDependencyAttribute processing: Couldn't satisfy a constraint. Class with Attribute: %s Bad candidate instantiated type: %s\r\n", pMT->GetDebugClassName(), candidateInstName.GetANSI(buffer));
5083 OutputDebugStringA(output);
5095 // This method has duplicated logic from bcl\system\collections\generic\comparer.cs
5097 static void SpecializeComparer(SString& ss, Instantiation& inst)
5099 STANDARD_VM_CONTRACT;
5101 if (inst.GetNumArgs() != 1) {
5102 _ASSERTE(!"Improper use of a TypeDependencyAttribute for Comparer");
5106 TypeHandle elemTypeHnd = inst[0];
5109 // Override the default ObjectComparer for special cases
5111 if (elemTypeHnd.CanCastTo(
5112 TypeHandle(MscorlibBinder::GetClass(CLASS__ICOMPARABLEGENERIC)).Instantiate(Instantiation(&elemTypeHnd, 1))))
5114 ss.Set(W("System.Collections.Generic.GenericComparer`1"));
5118 if (Nullable::IsNullableType(elemTypeHnd))
5120 Instantiation nullableInst = elemTypeHnd.AsMethodTable()->GetInstantiation();
5121 if (nullableInst[0].CanCastTo(
5122 TypeHandle(MscorlibBinder::GetClass(CLASS__ICOMPARABLEGENERIC)).Instantiate(nullableInst)))
5124 ss.Set(W("System.Collections.Generic.NullableComparer`1"));
5125 inst = nullableInst;
5130 if (elemTypeHnd.IsEnum())
5132 CorElementType et = elemTypeHnd.GetVerifierCorElementType();
5133 if (et == ELEMENT_TYPE_I1 ||
5134 et == ELEMENT_TYPE_I2 ||
5135 et == ELEMENT_TYPE_I4)
5137 ss.Set(W("System.Collections.Generic.Int32EnumComparer`1"));
5140 if (et == ELEMENT_TYPE_U1 ||
5141 et == ELEMENT_TYPE_U2 ||
5142 et == ELEMENT_TYPE_U4)
5144 ss.Set(W("System.Collections.Generic.UInt32EnumComparer`1"));
5147 if (et == ELEMENT_TYPE_I8)
5149 ss.Set(W("System.Collections.Generic.Int64EnumComparer`1"));
5152 if (et == ELEMENT_TYPE_U8)
5154 ss.Set(W("System.Collections.Generic.UInt64EnumComparer`1"));
5161 // This method has duplicated logic from bcl\system\collections\generic\equalitycomparer.cs
5162 // and matching logic in jitinterface.cpp
5164 static void SpecializeEqualityComparer(SString& ss, Instantiation& inst)
5166 STANDARD_VM_CONTRACT;
5168 if (inst.GetNumArgs() != 1) {
5169 _ASSERTE(!"Improper use of a TypeDependencyAttribute for EqualityComparer");
5173 TypeHandle elemTypeHnd = inst[0];
5176 // Override the default ObjectEqualityComparer for special cases
5178 if (elemTypeHnd.CanCastTo(
5179 TypeHandle(MscorlibBinder::GetClass(CLASS__IEQUATABLEGENERIC)).Instantiate(Instantiation(&elemTypeHnd, 1))))
5181 ss.Set(W("System.Collections.Generic.GenericEqualityComparer`1"));
5185 if (Nullable::IsNullableType(elemTypeHnd))
5187 Instantiation nullableInst = elemTypeHnd.AsMethodTable()->GetInstantiation();
5188 if (nullableInst[0].CanCastTo(
5189 TypeHandle(MscorlibBinder::GetClass(CLASS__IEQUATABLEGENERIC)).Instantiate(nullableInst)))
5191 ss.Set(W("System.Collections.Generic.NullableEqualityComparer`1"));
5192 inst = nullableInst;
5197 if (elemTypeHnd.IsEnum())
5199 // Note: We have different comparers for Short and SByte because for those types we need to make sure we call GetHashCode on the actual underlying type as the
5200 // implementation of GetHashCode is more complex than for the other types.
5201 CorElementType et = elemTypeHnd.GetVerifierCorElementType();
5202 if (et == ELEMENT_TYPE_I4 ||
5203 et == ELEMENT_TYPE_U4 ||
5204 et == ELEMENT_TYPE_U2 ||
5205 et == ELEMENT_TYPE_I2 ||
5206 et == ELEMENT_TYPE_U1 ||
5207 et == ELEMENT_TYPE_I1)
5209 ss.Set(W("System.Collections.Generic.EnumEqualityComparer`1"));
5212 else if (et == ELEMENT_TYPE_I8 ||
5213 et == ELEMENT_TYPE_U8)
5215 ss.Set(W("System.Collections.Generic.LongEnumEqualityComparer`1"));
5221 #ifdef FEATURE_COMINTEROP
5222 // Instantiation of WinRT types defined in non-WinRT module. This check is required to generate marshaling stubs for
5223 // instantiations of shadow WinRT types like EventHandler<ITracingStatusChangedEventArgs> in mscorlib.
5224 static BOOL IsInstantationOfShadowWinRTType(MethodTable * pMT)
5226 STANDARD_VM_CONTRACT;
5228 Instantiation inst = pMT->GetInstantiation();
5229 for (DWORD i = 0; i < inst.GetNumArgs(); i++)
5231 TypeHandle th = inst[i];
5232 if (th.IsProjectedFromWinRT() && !th.GetModule()->IsWindowsRuntimeModule())
5239 void CEEPreloader::ApplyTypeDependencyProductionsForType(TypeHandle t)
5241 STANDARD_VM_CONTRACT;
5243 // Only actual types
5247 MethodTable * pMT = t.AsMethodTable();
5249 if (!pMT->HasInstantiation() || pMT->ContainsGenericVariables())
5252 #ifdef FEATURE_COMINTEROP
5253 // At run-time, generic redirected interfaces and delegates need matching instantiations
5254 // of other types/methods in order to be marshaled across the interop boundary.
5255 if (m_image->GetModule()->IsWindowsRuntimeModule() || IsInstantationOfShadowWinRTType(pMT))
5257 // We only apply WinRT dependencies when compiling .winmd assemblies since redirected
5258 // types are heavily used in non-WinRT code as well and would bloat native images.
5259 if (pMT->IsLegalNonArrayWinRTType())
5262 WinMDAdapter::RedirectedTypeIndex index;
5263 if (WinRTInterfaceRedirector::ResolveRedirectedInterface(pMT, &index))
5265 // redirected interface needs the mscorlib-local definition of the corresponding WinRT type
5266 MethodTable *pWinRTMT = WinRTInterfaceRedirector::GetWinRTTypeForRedirectedInterfaceIndex(index);
5267 thWinRT = TypeHandle(pWinRTMT);
5269 // and matching stub methods
5270 WORD wNumSlots = pWinRTMT->GetNumVirtuals();
5271 for (WORD i = 0; i < wNumSlots; i++)
5273 MethodDesc *pAdapterMD = WinRTInterfaceRedirector::GetStubMethodForRedirectedInterface(
5276 TypeHandle::Interop_NativeToManaged,
5278 pMT->GetInstantiation());
5280 TriageMethodForZap(pAdapterMD, TRUE);
5283 if (WinRTDelegateRedirector::ResolveRedirectedDelegate(pMT, &index))
5285 // redirected delegate needs the mscorlib-local definition of the corresponding WinRT type
5286 thWinRT = TypeHandle(WinRTDelegateRedirector::GetWinRTTypeForRedirectedDelegateIndex(index));
5289 if (!thWinRT.IsNull())
5291 thWinRT = thWinRT.Instantiate(pMT->GetInstantiation());
5292 TriageTypeForZap(thWinRT, TRUE);
5296 #endif // FEATURE_COMINTEROP
5298 pMT = pMT->GetCanonicalMethodTable();
5300 // The TypeDependencyAttribute attribute is currently only allowed on mscorlib types
5301 // Don't even look for the attribute on types in other assemblies.
5302 if(!pMT->GetModule()->IsSystem()) {
5306 // Part 1. - check for an NGEN production rule specified by a use of CompilerServices.TypeDependencyAttribute
5307 // e.g. C<T> --> D<T>
5309 // For example, if C<int> is generated then we produce D<int>.
5311 // Normally NGEN can detect such productions through the process of compilation, but there are some
5312 // legitimate uses of reflection to generate generic instantiations which NGEN cannot detect.
5313 // In particular typically D<T> will have more constraints than C<T>, e.g.
5314 // class D<T> where T : IComparable<T>
5315 // Uses of dynamic constraints are an example - consider making a Comparer<T>, where we can have a
5316 // FastComparer<T> where T : IComparable<T>, and the "slow" version checks for the non-generic
5317 // IComparer interface.
5318 // Also, T[] : IList<T>, IReadOnlyList<T>, and both of those interfaces should have a type dependency on SZArrayHelper's generic methods.
5320 IMDInternalImport *pImport = pMT->GetMDImport();
5324 //walk all of the TypeDependencyAttributes
5325 MDEnumHolder hEnum(pImport);
5326 hr = pImport->EnumCustomAttributeByNameInit(pMT->GetCl(),
5327 g_CompilerServicesTypeDependencyAttribute, &hEnum);
5330 mdCustomAttribute tkAttribute;
5334 while (pImport->EnumNext(&hEnum, &tkAttribute))
5336 //get attribute and validate format
5337 if (FAILED(pImport->GetCustomAttributeAsBlob(
5339 reinterpret_cast<const void **>(&pbAttr),
5345 CustomAttributeParser cap(pbAttr, cbAttr);
5346 if (FAILED(cap.SkipProlog()))
5351 if (FAILED(cap.GetNonNullString(&szString, &cbString)))
5354 StackSString ss(SString::Utf8, szString, cbString);
5355 Instantiation inst = pMT->GetInstantiation();
5357 #ifndef FEATURE_FULL_NGEN
5358 // Do not expand non-canonical instantiations. They are not that expensive to create at runtime
5359 // using code:ClassLoader::CreateTypeHandleForNonCanonicalGenericInstantiation if necessary.
5360 if (!ClassLoader::IsCanonicalGenericInstantiation(inst))
5364 if (ss.Equals(W("System.Collections.Generic.ObjectComparer`1")))
5366 SpecializeComparer(ss, inst);
5369 if (ss.Equals(W("System.Collections.Generic.ObjectEqualityComparer`1")))
5371 SpecializeEqualityComparer(ss, inst);
5374 // Try to load the class using its name as a fully qualified name. If that fails,
5375 // then we try to load it in the assembly of the current class.
5376 TypeHandle typicalDepTH = TypeName::GetTypeUsingCASearchRules(ss.GetUnicode(), pMT->GetAssembly());
5378 _ASSERTE(!typicalDepTH.IsNull());
5379 // This attribute is currently only allowed to refer to mscorlib types
5380 _ASSERTE(typicalDepTH.GetModule()->IsSystem());
5381 if (!typicalDepTH.GetModule()->IsSystem())
5384 // For IList<T>, ICollection<T>, IEnumerable<T>, IReadOnlyCollection<T> & IReadOnlyList<T>, include SZArrayHelper's
5385 // generic methods (or at least the relevant ones) in the ngen image in
5386 // case someone casts a T[] to an IList<T> (or ICollection<T> or IEnumerable<T>, etc).
5387 if (MscorlibBinder::IsClass(typicalDepTH.AsMethodTable(), CLASS__SZARRAYHELPER))
5389 #ifdef FEATURE_FULL_NGEN
5390 if (pMT->GetNumGenericArgs() != 1 || !pMT->IsInterface()) {
5391 _ASSERTE(!"Improper use of a TypeDependencyAttribute for SZArrayHelper");
5394 TypeHandle elemTypeHnd = pMT->GetInstantiation()[0];
5395 if (elemTypeHnd.IsValueType())
5396 ApplyTypeDependencyForSZArrayHelper(pMT, elemTypeHnd);
5401 _ASSERTE(typicalDepTH.IsTypicalTypeDefinition());
5402 if (!typicalDepTH.IsTypicalTypeDefinition())
5405 // It certainly can't be immediately recursive...
5406 _ASSERTE(!typicalDepTH.GetMethodTable()->HasSameTypeDefAs(pMT));
5408 // We want to rule out some cases where we know for sure that the generated type
5409 // won't satisfy its constraints. However, some generated types may represent
5410 // canonicals in sets of shared instantaitions,
5412 if (CanSatisfyConstraints(typicalDepTH.GetInstantiation(), inst))
5414 TypeHandle instDepTH =
5415 ClassLoader::LoadGenericInstantiationThrowing(typicalDepTH.GetModule(), typicalDepTH.GetCl(), inst);
5417 _ASSERTE(!instDepTH.ContainsGenericVariables());
5418 _ASSERTE(instDepTH.GetNumGenericArgs() == typicalDepTH.GetNumGenericArgs());
5419 _ASSERTE(instDepTH.GetMethodTable()->HasSameTypeDefAs(typicalDepTH.GetMethodTable()));
5421 // OK, add the generated type to the dependency set
5422 TriageTypeForZap(instDepTH, TRUE);
5426 } // CEEPreloader::ApplyTypeDependencyProductionsForType
5429 // Given IEnumerable<Foo>, we want to add System.SZArrayHelper.GetEnumerator<Foo>
5430 // to the ngen image. This way we can cast a T[] to an IList<T> and
5431 // use methods on it (from SZArrayHelper) without pulling in the JIT.
5432 // Do the same for ICollection<T>/IReadOnlyCollection<T> and
5433 // IList<T>/IReadOnlyList<T>, but only add the relevant methods
5434 // from those interfaces.
5435 void CEEPreloader::ApplyTypeDependencyForSZArrayHelper(MethodTable * pInterfaceMT, TypeHandle elemTypeHnd)
5437 STANDARD_VM_CONTRACT;
5439 _ASSERTE(elemTypeHnd.AsMethodTable()->IsValueType());
5441 // We expect this to only be called for IList<T>/IReadOnlyList<T>, ICollection<T>/IReadOnlyCollection<T>, IEnumerable<T>.
5442 _ASSERTE(pInterfaceMT->IsInterface());
5443 _ASSERTE(pInterfaceMT->GetNumGenericArgs() == 1);
5445 // This is the list of methods that don't throw exceptions on SZArrayHelper.
5446 static const BinderMethodID SZArrayHelperMethodIDs[] = {
5447 // Read-only methods that are present on both regular and read-only interfaces.
5448 METHOD__SZARRAYHELPER__GETENUMERATOR,
5449 METHOD__SZARRAYHELPER__GET_COUNT,
5450 METHOD__SZARRAYHELPER__GET_ITEM,
5451 // The rest of the methods is present on regular interfaces only.
5452 METHOD__SZARRAYHELPER__SET_ITEM,
5453 METHOD__SZARRAYHELPER__COPYTO,
5454 METHOD__SZARRAYHELPER__INDEXOF,
5455 METHOD__SZARRAYHELPER__CONTAINS };
5457 static const int cReadOnlyMethods = 3;
5458 static const int cAllMethods = 7;
5460 static const BinderMethodID LastMethodOnGenericArrayInterfaces[] = {
5461 METHOD__SZARRAYHELPER__GETENUMERATOR, // Last method of IEnumerable<T>
5462 METHOD__SZARRAYHELPER__REMOVE, // Last method of ICollection<T>.
5463 METHOD__SZARRAYHELPER__REMOVEAT, // Last method of IList<T>
5466 // Assuming the binder ID's are properly laid out in mscorlib.h
5468 for(unsigned int i=0; i < NumItems(LastMethodOnGenericArrayInterfaces) - 1; i++) {
5469 _ASSERTE(LastMethodOnGenericArrayInterfaces[i] < LastMethodOnGenericArrayInterfaces[i+1]);
5473 MethodTable* pExactMT = MscorlibBinder::GetClass(CLASS__SZARRAYHELPER);
5475 // Subtract one from the non-generic IEnumerable that the generic IEnumerable<T>
5477 unsigned inheritanceDepth = pInterfaceMT->GetNumInterfaces() - 1;
5478 PREFIX_ASSUME(0 <= inheritanceDepth && inheritanceDepth < NumItems(LastMethodOnGenericArrayInterfaces));
5480 // Read-only interfaces happen to always have one method
5481 bool fIsReadOnly = pInterfaceMT->GetNumVirtuals() == 1;
5483 for(int i=0; i < (fIsReadOnly ? cReadOnlyMethods : cAllMethods); i++)
5485 // Check whether the method applies for this type.
5486 if (SZArrayHelperMethodIDs[i] > LastMethodOnGenericArrayInterfaces[inheritanceDepth])
5489 MethodDesc * pPrimaryMD = MscorlibBinder::GetMethod(SZArrayHelperMethodIDs[i]);
5491 MethodDesc * pInstantiatedMD = MethodDesc::FindOrCreateAssociatedMethodDesc(pPrimaryMD,
5492 pExactMT, false, Instantiation(&elemTypeHnd, 1), false);
5494 TriageMethodForZap(pInstantiatedMD, true);
5499 void CEEPreloader::AddTypeToTransitiveClosureOfInstantiations(CORINFO_CLASS_HANDLE handle)
5501 STANDARD_VM_CONTRACT;
5503 TriageTypeForZap((TypeHandle) handle, TRUE);
5506 const unsigned MAX_ZAP_INSTANTIATION_NESTING = 10;
5508 BOOL IsGenericTooDeeplyNested(TypeHandle t)
5516 //if this type is more than N levels nested deep, do not add it to the
5517 //closure. Build a queue for a DFS of the depth of instantiation.
5519 //the current index in the queue we're visiting
5520 int currentQueueIdx; //use -1 to indicate that we're done.
5521 //the current generic arg type.
5522 TypeHandle currentVisitingType[MAX_ZAP_INSTANTIATION_NESTING];
5524 //the ordinal in the GetInstantiation for the current type (over [0,
5525 //GetNumGenericArg())
5526 unsigned currentGenericArgEdge[MAX_ZAP_INSTANTIATION_NESTING];
5528 //initialize the DFS.
5529 memset(currentGenericArgEdge, 0, sizeof(currentGenericArgEdge));
5530 currentVisitingType[0] = t;
5531 currentQueueIdx = 0;
5533 while( currentQueueIdx >= 0 )
5535 //see if we're done with this node
5536 if( currentVisitingType[currentQueueIdx].GetNumGenericArgs()
5537 <= currentGenericArgEdge[currentQueueIdx] )
5543 //more edges to visit. So visit one edge
5544 _ASSERTE(currentGenericArgEdge[currentQueueIdx] < currentVisitingType[currentQueueIdx].GetNumGenericArgs());
5545 TypeHandle current = currentVisitingType[currentQueueIdx].GetInstantiation()[currentGenericArgEdge[currentQueueIdx]];
5546 ++currentGenericArgEdge[currentQueueIdx];
5547 //only value types cause a problem because of "approximate" type
5548 //loading, so only worry about scanning value type arguments.
5549 if( current.HasInstantiation() && current.IsValueType() )
5551 //new edge. Make sure there is space in the queue.
5552 if( (currentQueueIdx + 1) >= (int)NumItems(currentGenericArgEdge) )
5554 //exceeded the allowable depth. Stop processing.
5560 currentGenericArgEdge[currentQueueIdx] = 0;
5561 currentVisitingType[currentQueueIdx] = current;
5570 void CEEPreloader::TriageTypeForZap(TypeHandle th, BOOL fAcceptIfNotSure, BOOL fExpandDependencies)
5572 STANDARD_VM_CONTRACT;
5574 // We care about param types only
5575 if (th.IsTypicalTypeDefinition() && !th.IsTypeDesc())
5578 // We care about types from our module only
5579 if (m_image->GetModule() != th.GetLoaderModule())
5582 // Check if we have decided to accept this type already.
5583 if (m_acceptedTypes.Lookup(th) != NULL)
5586 // Check if we have decided to reject this type already.
5587 if (m_rejectedTypes.Lookup(th) != NULL)
5590 enum { Investigate, Accepted, Rejected } triage = Investigate;
5592 const char * rejectReason = NULL;
5594 // TypeVarTypeDesc are saved via links from code:Module::m_GenericParamToDescMap
5595 if (th.IsGenericVariable())
5598 rejectReason = "type is a Generic variable";
5602 /* Consider this example:
5605 class B<U> : A<U> {}
5618 The open instantiations can be divided into the following 3 categories:
5620 1. A<T>, B<U>, A<U>, C<V>, B<V>, A<V> are open instantiations involving
5621 ELEMENT_TYPE_VARs that need to be saved in the ngen image.
5622 2. List<V> is an instantiations that also involves ELEMENT_TYPE_VARs.
5623 However, it need not be saved since it will only be needed during the
5624 verification of foo<W>().
5625 3. C<W>, A<W>, B<A<W>> are open instantiations involving ELEMENT_TYPE_MVARs
5626 that need not be saved since they will only be needed during the
5627 verification of foo<W>().
5629 Distinguishing between 1 and 2 requires walking C<V> and determining
5630 which ones are field/parent/interface types required by c<V>. However,
5631 category 3 is easy to detect, and can easily be pruned out. Hence,
5632 we pass in methodTypeVarsOnly=TRUE here.
5634 if (th.ContainsGenericVariables(TRUE/*methodTypeVarsOnly*/))
5637 rejectReason = "type contains method generic variables";
5641 // Filter out weird cases we do not care about.
5642 if (!m_image->GetModule()->GetAvailableParamTypes()->ContainsValue(th))
5645 rejectReason = "type is not in the current module";
5649 // Reject invalid generic instantiations. They will not be fully loaded
5650 // as they will throw a TypeLoadException before they reach CLASS_LOAD_LEVEL_FINAL.
5651 if (!th.IsFullyLoaded())
5653 // This may load new types. May load new types.
5654 ClassLoader::TryEnsureLoaded(th);
5656 if (!th.IsFullyLoaded())
5659 rejectReason = "type could not be fully loaded, possibly because it does not satisfy its constraints";
5664 // Do not save any types containing generic class parameters from another module
5665 Module *pOpenModule;
5666 pOpenModule = th.GetDefiningModuleForOpenType();
5667 if (pOpenModule != NULL && pOpenModule != m_image->GetModule())
5670 rejectReason = "type contains generic variables from another module";
5674 // Always store items in their preferred zap module even if we are not sure
5675 if (Module::GetPreferredZapModuleForTypeHandle(th) == m_image->GetModule())
5681 #ifdef FEATURE_FULL_NGEN
5682 // Only save arrays and other param types in their preferred zap modules,
5683 // i.e. never duplicate them.
5684 if (th.IsTypeDesc() || th.IsArrayType())
5687 rejectReason = "type is a TypeDesc";
5692 // Do not save instantiations found in one of our hardbound dependencies
5693 PtrHashMap::PtrIterator iter = GetAppDomain()->ToCompilationDomain()->IterateHardBoundModules();
5694 for (/**/; !iter.end(); ++iter)
5696 Module * hardBoundModule = (Module*)iter.GetValue();
5697 if (hardBoundModule->GetAvailableParamTypes()->ContainsValue(th))
5700 rejectReason = "type was found in a hardbound dependency";
5706 // We are not really sure about this type. Accept it only if we have been asked to.
5707 if (fAcceptIfNotSure)
5709 if (!m_fSpeculativeTriage)
5711 // We will take a look later before we actually start compiling the instantiations
5712 m_speculativeTypes.Append(th);
5713 m_acceptedTypes.Add(th);
5721 rejectReason = "type is not in the preferred module";
5729 m_acceptedTypes.Add(th);
5730 if (fExpandDependencies)
5732 ExpandTypeDependencies(th);
5738 m_rejectedTypes.Add(th);
5741 // It is expensive to call th.GetName, only do it when we are actually logging
5742 if (LoggingEnabled())
5745 th.GetName(typeName);
5746 LOG((LF_ZAP, LL_INFO10000, "TriageTypeForZap rejects %S (%08x) because %s\n",
5747 typeName.GetUnicode(), th.AsPtr(), rejectReason));
5753 // We have not found a compeling reason to accept or reject the type yet. Maybe next time...
5758 void CEEPreloader::ExpandTypeDependencies(TypeHandle th)
5760 STANDARD_VM_CONTRACT;
5762 if (th.IsTypeDesc())
5765 MethodTable* pMT = th.AsMethodTable();
5767 if (pMT->IsCanonicalMethodTable())
5769 // Cutoff infinite recursion.
5770 if (!IsGenericTooDeeplyNested(th))
5772 // Make sure all methods are compiled
5773 // We only want to check the method bodies owned by this type,
5774 // and not any method bodies owned by a parent type, as the
5775 // parent type may not get saved in this ngen image.
5776 MethodTable::IntroducedMethodIterator itr(pMT);
5777 for (/**/; itr.IsValid(); itr.Next())
5779 AddToUncompiledMethods(itr.GetMethodDesc(), FALSE);
5785 // Make sure canonical method table is saved
5786 TriageTypeForZap(pMT->GetCanonicalMethodTable(), TRUE);
5789 if (pMT->SupportsGenericInterop(TypeHandle::Interop_ManagedToNative))
5791 MethodTable::IntroducedMethodIterator itr(pMT->GetCanonicalMethodTable());
5792 for (/**/; itr.IsValid(); itr.Next())
5794 MethodDesc *pMD = itr.GetMethodDesc();
5796 if (!pMD->HasMethodInstantiation())
5798 if (pMT->IsInterface() || !pMD->IsSharedByGenericInstantiations())
5800 pMD = MethodDesc::FindOrCreateAssociatedMethodDesc(
5803 FALSE, // forceBoxedEntryPoint
5804 Instantiation(), // methodInst
5805 FALSE, // allowInstParam
5806 TRUE); // forceRemotableMethod
5810 _ASSERTE(pMT->IsDelegate());
5811 pMD = InstantiatedMethodDesc::FindOrCreateExactClassMethod(pMT, pMD);
5814 AddToUncompiledMethods(pMD, TRUE);
5819 // Make sure parent type is saved
5820 TriageTypeForZap(pMT->GetParentMethodTable(), TRUE);
5822 // Make sure all instantiation arguments are saved
5823 Instantiation inst = pMT->GetInstantiation();
5824 for (DWORD iArg = 0; iArg < inst.GetNumArgs(); iArg++)
5826 TriageTypeForZap(inst[iArg], TRUE);
5829 // Make sure all interfaces implemeted by the class are saved
5830 MethodTable::InterfaceMapIterator intIterator = pMT->IterateInterfaceMap();
5831 while (intIterator.Next())
5833 TriageTypeForZap(intIterator.GetInterface(), TRUE);
5836 // Make sure aprox types for all fields are saved
5837 ApproxFieldDescIterator fdIterator(pMT, ApproxFieldDescIterator::ALL_FIELDS);
5839 while ((pFD = fdIterator.Next()) != NULL)
5841 if (pFD->GetFieldType() == ELEMENT_TYPE_VALUETYPE)
5843 TriageTypeForZap(pFD->GetFieldTypeHandleThrowing(), TRUE);
5847 // Make sure types for all generic static fields are saved
5849 if (pMT->HasGenericsStaticsInfo())
5851 FieldDesc *pGenStaticFields = pMT->GetGenericsStaticFieldDescs();
5852 DWORD nFields = pMT->GetNumStaticFields();
5853 for (DWORD iField = 0; iField < nFields; iField++)
5855 FieldDesc* pField = &pGenStaticFields[iField];
5856 if (pField->GetFieldType() == ELEMENT_TYPE_VALUETYPE)
5858 TriageTypeForZap(pField->GetFieldTypeHandleThrowing(), TRUE);
5863 // Expand type using the custom rules. May load new types.
5864 ApplyTypeDependencyProductionsForType(th);
5867 // Triage instantiations of generic methods
5869 void CEEPreloader::TriageMethodForZap(MethodDesc* pMD, BOOL fAcceptIfNotSure, BOOL fExpandDependencies)
5871 STANDARD_VM_CONTRACT;
5873 // Submit the method type for triage
5874 TriageTypeForZap(TypeHandle(pMD->GetMethodTable()), fAcceptIfNotSure);
5876 // We care about instantiated methods only
5877 if (pMD->IsTypicalMethodDefinition())
5880 // We care about methods from our module only
5881 if (m_image->GetModule() != pMD->GetLoaderModule())
5884 // Check if we have decided to accept this method already.
5885 if (m_acceptedMethods.Lookup(pMD) != NULL)
5888 // Check if we have decided to reject this method already.
5889 if (m_rejectedMethods.Lookup(pMD) != NULL)
5892 enum { Investigate, Accepted, Rejected } triage = Investigate;
5894 const char * rejectReason = NULL;
5896 // Do not save open methods
5897 if (pMD->ContainsGenericVariables())
5900 rejectReason = "method contains method generic variables";
5904 // Always store items in their preferred zap module even if we are not sure
5905 if (Module::GetPreferredZapModuleForMethodDesc(pMD) == m_image->GetModule())
5911 #ifdef FEATURE_FULL_NGEN
5913 // Do not save instantiations found in one of our hardbound dependencies
5914 PtrHashMap::PtrIterator iter = GetAppDomain()->ToCompilationDomain()->IterateHardBoundModules();
5915 for (/**/; !iter.end(); ++iter)
5917 Module * hardBoundModule = (Module*)iter.GetValue();
5918 if (hardBoundModule->GetInstMethodHashTable()->ContainsMethodDesc(pMD))
5921 rejectReason = "method was found in a hardbound dependency";
5927 // We are not really sure about this method. Accept it only if we have been asked to.
5928 if (fAcceptIfNotSure)
5930 // It does not seem worth it to go through extra hoops to eliminate redundant
5931 // speculative method instatiations from softbound dependencies like we do for types
5932 // if (!m_fSpeculativeTriage)
5934 // // We will take a look later before we actually start compiling the instantiations
5949 m_acceptedMethods.Add(pMD);
5950 if (fExpandDependencies)
5952 ExpandMethodDependencies(pMD);
5957 m_rejectedMethods.Add(pMD);
5958 LOG((LF_ZAP, LL_INFO10000, "TriageMethodForZap rejects %s (%08x) because %s\n",
5959 pMD->m_pszDebugMethodName, pMD, rejectReason));
5963 // We have not found a compeling reason to accept or reject the method yet. Maybe next time...
5968 void CEEPreloader::ExpandMethodDependencies(MethodDesc * pMD)
5970 STANDARD_VM_CONTRACT;
5972 AddToUncompiledMethods(pMD, FALSE);
5975 // Make sure all instantiation arguments are saved
5976 Instantiation inst = pMD->GetMethodInstantiation();
5977 for (DWORD iArg = 0; iArg < inst.GetNumArgs(); iArg++)
5979 TriageTypeForZap(inst[iArg], TRUE);
5983 // Make sure to add wrapped method desc
5984 if (pMD->IsWrapperStub())
5985 TriageMethodForZap(pMD->GetWrappedMethodDesc(), TRUE);
5988 void CEEPreloader::TriageTypeFromSoftBoundModule(TypeHandle th, Module * pSoftBoundModule)
5990 STANDARD_VM_CONTRACT;
5992 // We care about types from our module only
5993 if (m_image->GetModule() != th.GetLoaderModule())
5996 // Nothing to do if we have rejected the type already.
5997 if (m_rejectedTypes.Lookup(th) != NULL)
6000 // We make guarantees about types living in its own PZM only
6001 if (Module::GetPreferredZapModuleForTypeHandle(th) != pSoftBoundModule)
6004 // Reject the type - it is guaranteed to be saved in PZM
6005 m_rejectedTypes.Add(th);
6007 if (!th.IsTypeDesc())
6009 // Reject the canonical method table if possible.
6010 MethodTable* pMT = th.AsMethodTable();
6011 if (!pMT->IsCanonicalMethodTable())
6012 TriageTypeFromSoftBoundModule(pMT->GetCanonicalMethodTable(), pSoftBoundModule);
6014 // Reject parent method table if possible.
6015 TriageTypeFromSoftBoundModule(pMT->GetParentMethodTable(), pSoftBoundModule);
6017 // Reject all interfaces implemented by the type if possible.
6018 MethodTable::InterfaceMapIterator intIterator = pMT->IterateInterfaceMap();
6019 while (intIterator.Next())
6021 TriageTypeFromSoftBoundModule(intIterator.GetInterface(), pSoftBoundModule);
6024 // It does not seem worth it to reject the remaining items
6025 // expanded by CEEPreloader::ExpandTypeDependencies here.
6029 #ifdef FEATURE_FULL_NGEN
6030 static TypeHandle TryToLoadTypeSpecHelper(Module * pModule, PCCOR_SIGNATURE pSig, ULONG cSig)
6032 STANDARD_VM_CONTRACT;
6038 SigPointer p(pSig, cSig);
6039 SigTypeContext typeContext; // empty context is OK: encoding should not contain type variables.
6041 th = p.GetTypeHandleThrowing(pModule, &typeContext, ClassLoader::DontLoadTypes);
6046 EX_END_CATCH(SwallowAllExceptions)
6051 void CEEPreloader::TriageTypeSpecsFromSoftBoundModule(Module * pSoftBoundModule)
6053 STANDARD_VM_CONTRACT;
6056 // Reject all typespecs that are guranteed to be found in soft bound PZM
6059 IMDInternalImport *pInternalImport = pSoftBoundModule->GetMDImport();
6061 HENUMInternalHolder hEnum(pInternalImport);
6062 hEnum.EnumAllInit(mdtTypeSpec);
6065 while (pInternalImport->EnumNext(&hEnum, &tk))
6068 PCCOR_SIGNATURE pSig;
6070 if (FAILED(pInternalImport->GetTypeSpecFromToken(tk, &pSig, &cSig)))
6076 // Check all types specs that do not contain variables
6077 if (SigPointer(pSig, cSig).IsPolyType(NULL) == hasNoVars)
6079 TypeHandle th = TryToLoadTypeSpecHelper(pSoftBoundModule, pSig, cSig);
6084 TriageTypeFromSoftBoundModule(th, pSoftBoundModule);
6089 void CEEPreloader::TriageSpeculativeType(TypeHandle th)
6091 STANDARD_VM_CONTRACT;
6093 // Nothing to do if we have rejected the type already
6094 if (m_rejectedTypes.Lookup(th) != NULL)
6097 Module * pPreferredZapModule = Module::GetPreferredZapModuleForTypeHandle(th);
6098 BOOL fHardBoundPreferredZapModule = FALSE;
6101 // Even though we have done this check already earlier, do it again here in case we have picked up
6102 // any eager-bound dependency in the meantime
6104 // Do not save instantiations found in one of our eager-bound dependencies
6105 PtrHashMap::PtrIterator iter = GetAppDomain()->ToCompilationDomain()->IterateHardBoundModules();
6106 for (/**/; !iter.end(); ++iter)
6108 Module * hardBoundModule = (Module*)iter.GetValue();
6109 if (hardBoundModule->GetAvailableParamTypes()->ContainsValue(th))
6111 m_rejectedTypes.Add(th);
6115 if (hardBoundModule == pPreferredZapModule)
6117 fHardBoundPreferredZapModule = TRUE;
6121 if (!fHardBoundPreferredZapModule && !pPreferredZapModule->AreTypeSpecsTriaged())
6123 // Reject all types that are guaranteed to be instantiated in soft bound PZM
6124 TriageTypeSpecsFromSoftBoundModule(pPreferredZapModule);
6125 pPreferredZapModule->SetTypeSpecsTriaged();
6127 if (m_rejectedTypes.Lookup(th) != NULL)
6131 // We have to no other option but to accept and expand the type
6132 ExpandTypeDependencies(th);
6135 void CEEPreloader::TriageSpeculativeInstantiations()
6137 STANDARD_VM_CONTRACT;
6139 // Get definitive triage answer for speculative types that we have run into earlier
6140 // Note that m_speculativeTypes may be growing as this loop runs
6141 for (COUNT_T i = 0; i < m_speculativeTypes.GetCount(); i++)
6143 TriageSpeculativeType(m_speculativeTypes[i]);
6146 // We are done - the array of speculative types is no longer necessary
6147 m_speculativeTypes.Clear();
6149 #endif // FEATURE_FULL_NGEN
6151 BOOL CEEPreloader::TriageForZap(BOOL fAcceptIfNotSure, BOOL fExpandDependencies)
6153 STANDARD_VM_CONTRACT;
6155 DWORD dwNumTypes = m_image->GetModule()->GetAvailableParamTypes()->GetCount();
6156 DWORD dwNumMethods = m_image->GetModule()->GetInstMethodHashTable()->GetCount();
6160 // Create a local copy in case the new elements are added to the hashtable during population
6161 InlineSArray<TypeHandle, 20> pTypes;
6163 // Make sure the iterator is destroyed before there is a chance of loading new types
6165 EETypeHashTable* pTable = m_image->GetModule()->GetAvailableParamTypes();
6167 EETypeHashTable::Iterator it(pTable);
6168 EETypeHashEntry *pEntry;
6169 while (pTable->FindNext(&it, &pEntry))
6171 TypeHandle th = pEntry->GetTypeHandle();
6172 if (m_acceptedTypes.Lookup(th) == NULL && m_rejectedTypes.Lookup(th) == NULL)
6177 for(COUNT_T i = 0; i < pTypes.GetCount(); i ++)
6179 TriageTypeForZap(pTypes[i], fAcceptIfNotSure, fExpandDependencies);
6185 // Create a local copy in case the new elements are added to the hashtable during population
6186 InlineSArray<MethodDesc*, 20> pMethods;
6188 // Make sure the iterator is destroyed before there is a chance of loading new methods
6190 InstMethodHashTable* pTable = m_image->GetModule()->GetInstMethodHashTable();
6192 InstMethodHashTable::Iterator it(pTable);
6193 InstMethodHashEntry *pEntry;
6194 while (pTable->FindNext(&it, &pEntry))
6196 MethodDesc* pMD = pEntry->GetMethod();
6197 if (m_acceptedMethods.Lookup(pMD) == NULL && m_rejectedMethods.Lookup(pMD) == NULL)
6198 pMethods.Append(pMD);
6202 for(COUNT_T i = 0; i < pMethods.GetCount(); i ++)
6204 TriageMethodForZap(pMethods[i], fAcceptIfNotSure, fExpandDependencies);
6208 // Returns TRUE if new types or methods has been added by the triage
6209 return (dwNumTypes != m_image->GetModule()->GetAvailableParamTypes()->GetCount()) ||
6210 (dwNumMethods != m_image->GetModule()->GetInstMethodHashTable()->GetCount());
6213 void CEEPreloader::PrePrepareMethodIfNecessary(CORINFO_METHOD_HANDLE hMethod)
6215 STANDARD_VM_CONTRACT;
6219 static void SetStubMethodDescOnInteropMethodDesc(MethodDesc* pInteropMD, MethodDesc* pStubMD, bool fReverseStub)
6227 // We store NGENed stubs on these MethodDesc types
6228 PRECONDITION(pInteropMD->IsNDirect() || pInteropMD->IsComPlusCall() || pInteropMD->IsGenericComPlusCall() || pInteropMD->IsEEImpl());
6232 if (pInteropMD->IsNDirect())
6234 _ASSERTE(!fReverseStub);
6235 NDirectMethodDesc* pNMD = (NDirectMethodDesc*)pInteropMD;
6236 pNMD->ndirect.m_pStubMD.SetValue(pStubMD);
6238 #ifdef FEATURE_COMINTEROP
6239 else if (pInteropMD->IsComPlusCall() || pInteropMD->IsGenericComPlusCall())
6241 _ASSERTE(!fReverseStub);
6242 ComPlusCallInfo *pComInfo = ComPlusCallInfo::FromMethodDesc(pInteropMD);
6243 pComInfo->m_pStubMD.SetValue(pStubMD);
6245 #endif // FEATURE_COMINTEROP
6246 else if (pInteropMD->IsEEImpl())
6248 DelegateEEClass* pDelegateClass = (DelegateEEClass*)pInteropMD->GetClass();
6251 pDelegateClass->m_pReverseStubMD = pStubMD;
6255 #ifdef FEATURE_COMINTEROP
6256 // We don't currently NGEN both the P/Invoke and WinRT stubs for WinRT delegates.
6257 // If that changes, this function will need an extra parameter to tell what kind
6258 // of stub is being passed.
6259 if (pInteropMD->GetMethodTable()->IsWinRTDelegate())
6261 pDelegateClass->m_pComPlusCallInfo->m_pStubMD.SetValue(pStubMD);
6264 #endif // FEATURE_COMINTEROP
6266 pDelegateClass->m_pForwardStubMD = pStubMD;
6272 UNREACHABLE_MSG("unexpected type of MethodDesc");
6276 MethodDesc * CEEPreloader::CompileMethodStubIfNeeded(
6278 MethodDesc *pStubMD,
6279 ICorCompilePreloader::CORCOMPILE_CompileStubCallback pfnCallback,
6280 LPVOID pCallbackContext)
6282 STANDARD_VM_CONTRACT;
6284 LOG((LF_ZAP, LL_INFO10000, "NGEN_ILSTUB: %s::%s -> %s::%s\n",
6285 pMD->m_pszDebugClassName, pMD->m_pszDebugMethodName, pStubMD->m_pszDebugClassName, pStubMD->m_pszDebugMethodName));
6287 // It is possible that the StubMD is a normal method pointed by InteropStubMethodAttribute,
6288 // and in that case we don't need to compile it here
6289 if (pStubMD->IsDynamicMethod())
6291 if (!pStubMD->AsDynamicMethodDesc()->GetILStubResolver()->IsCompiled())
6293 CORJIT_FLAGS jitFlags = pStubMD->AsDynamicMethodDesc()->GetILStubResolver()->GetJitFlags();
6295 pfnCallback(pCallbackContext, (CORINFO_METHOD_HANDLE)pStubMD, jitFlags);
6298 #ifndef FEATURE_FULL_NGEN // Deduplication
6299 const DuplicateMethodEntry * pDuplicate = m_duplicateMethodsHash.LookupPtr(pStubMD);
6300 if (pDuplicate != NULL)
6301 return pDuplicate->pDuplicateMD;
6305 //We do not store ILStubs so if the compilation failed for them
6306 //It does not make sense to keep the MD corresponding to the IL
6307 if (pStubMD->IsILStub() && m_image->GetCodeAddress(pStubMD) == NULL)
6313 void CEEPreloader::GenerateMethodStubs(
6314 CORINFO_METHOD_HANDLE hMethod,
6315 bool fNgenProfilerImage,
6316 CORCOMPILE_CompileStubCallback pfnCallback,
6317 LPVOID pCallbackContext)
6322 PRECONDITION(hMethod != NULL && pfnCallback != NULL);
6326 MethodDesc* pMD = GetMethod(hMethod);
6327 MethodDesc* pStubMD = NULL;
6329 // Do not generate IL stubs when generating ReadyToRun images
6330 // This prevents versionability concerns around IL stubs exposing internal
6331 // implementation details of the CLR.
6332 if (IsReadyToRunCompilation())
6335 DWORD dwNGenStubFlags = NDIRECTSTUB_FL_NGENEDSTUB;
6337 if (fNgenProfilerImage)
6338 dwNGenStubFlags |= NDIRECTSTUB_FL_NGENEDSTUBFORPROFILING;
6341 // Generate IL stubs. If failed, we go through normal NGEN path
6342 // Catch any exceptions that occur when we try to create the IL_STUB
6347 // Take care of forward stubs
6349 if (pMD->IsNDirect())
6351 NDirectMethodDesc* pNMD = (NDirectMethodDesc*)pMD;
6352 PInvokeStaticSigInfo sigInfo;
6353 NDirect::PopulateNDirectMethodDesc(pNMD, &sigInfo);
6354 pStubMD = NDirect::GetILStubMethodDesc((NDirectMethodDesc*)pMD, &sigInfo, dwNGenStubFlags);
6356 #ifdef FEATURE_COMINTEROP
6357 else if (pMD->IsComPlusCall() || pMD->IsGenericComPlusCall())
6359 if (MethodNeedsForwardComStub(pMD, m_image))
6361 // Look for predefined IL stubs in forward com interop scenario.
6362 // If we've found a stub, that's what we'll use
6364 ComPlusCall::PopulateComPlusCallMethodDesc(pMD, &dwStubFlags);
6365 if (FAILED(FindPredefinedILStubMethod(pMD, dwStubFlags, &pStubMD)))
6367 pStubMD = ComPlusCall::GetILStubMethodDesc(pMD, dwStubFlags | dwNGenStubFlags);
6371 #endif // FEATURE_COMINTEROP
6372 else if (pMD->IsEEImpl())
6374 MethodTable* pMT = pMD->GetMethodTable();
6375 CONSISTENCY_CHECK(pMT->IsDelegate());
6377 // we can filter out non-WinRT generic delegates right off the top
6378 if (!pMD->HasClassOrMethodInstantiation() || pMT->IsProjectedFromWinRT()
6379 #ifdef FEATURE_COMINTEROP
6380 || WinRTTypeNameConverter::IsRedirectedType(pMT)
6381 #endif // FEATURE_COMINTEROP
6384 if (COMDelegate::IsDelegateInvokeMethod(pMD)) // build forward stub
6386 #ifdef FEATURE_COMINTEROP
6387 if ((pMT->IsProjectedFromWinRT() || WinRTTypeNameConverter::IsRedirectedType(pMT)) &&
6388 (!pMT->HasInstantiation() || pMT->SupportsGenericInterop(TypeHandle::Interop_ManagedToNative))) // filter out shared generics
6390 // Build the stub for all WinRT delegates, these will definitely be used for interop.
6391 if (pMT->IsLegalNonArrayWinRTType())
6393 COMDelegate::PopulateComPlusCallInfo(pMT);
6394 pStubMD = COMDelegate::GetILStubMethodDesc((EEImplMethodDesc *)pMD, dwNGenStubFlags);
6398 #endif // FEATURE_COMINTEROP
6400 // Build the stub only if the delegate is decorated with UnmanagedFunctionPointerAttribute.
6401 // Forward delegate stubs are rare so we require this opt-in to avoid bloating NGEN images.
6403 if (S_OK == pMT->GetMDImport()->GetCustomAttributeByName(
6404 pMT->GetCl(), g_UnmanagedFunctionPointerAttribute, NULL, NULL))
6406 pStubMD = COMDelegate::GetILStubMethodDesc((EEImplMethodDesc *)pMD, dwNGenStubFlags);
6413 // compile the forward stub
6414 if (pStubMD != NULL)
6416 pStubMD = CompileMethodStubIfNeeded(pMD, pStubMD, pfnCallback, pCallbackContext);
6418 // We store the MethodDesc of the Stub on the NDirectMethodDesc/ComPlusCallMethodDesc/DelegateEEClass
6419 // that we can recover the stub MethodDesc at prestub time, do the fixups, and wire up the native code
6420 if (pStubMD != NULL)
6422 SetStubMethodDescOnInteropMethodDesc(pMD, pStubMD, false /* fReverseStub */);
6430 LOG((LF_ZAP, LL_WARNING, "NGEN_ILSTUB: Generating forward interop stub FAILED: %s::%s\n", pMD->m_pszDebugClassName, pMD->m_pszDebugMethodName));
6432 EX_END_CATCH(RethrowTransientExceptions);
6435 // Now take care of reverse P/Invoke stubs for delegates
6437 if (pMD->IsEEImpl() && COMDelegate::IsDelegateInvokeMethod(pMD))
6439 // Reverse P/Invoke is not supported for generic methods and WinRT delegates
6440 if (!pMD->HasClassOrMethodInstantiation() && !pMD->GetMethodTable()->IsProjectedFromWinRT())
6445 // on x86, we call the target directly if Invoke has a no-marshal signature
6446 if (NDirect::MarshalingRequired(pMD))
6447 #endif // _TARGET_X86_
6449 PInvokeStaticSigInfo sigInfo(pMD);
6450 pStubMD = UMThunkMarshInfo::GetILStubMethodDesc(pMD, &sigInfo, NDIRECTSTUB_FL_DELEGATE | dwNGenStubFlags);
6452 if (pStubMD != NULL)
6454 // compile the reverse stub
6455 pStubMD = CompileMethodStubIfNeeded(pMD, pStubMD, pfnCallback, pCallbackContext);
6457 // We store the MethodDesc of the Stub on the DelegateEEClass
6458 if (pStubMD != NULL)
6460 SetStubMethodDescOnInteropMethodDesc(pMD, pStubMD, true /* fReverseStub */);
6467 LOG((LF_ZAP, LL_WARNING, "NGEN_ILSTUB: Generating reverse interop stub for delegate FAILED: %s::%s\n", pMD->m_pszDebugClassName, pMD->m_pszDebugMethodName));
6469 EX_END_CATCH(RethrowTransientExceptions);
6473 #ifdef FEATURE_COMINTEROP
6475 // And finally generate reverse COM stubs
6479 // The method doesn't have to have a special type to be exposed to COM, in particular it doesn't
6480 // have to be ComPlusCallMethodDesc. However, it must have certain properties (custom attributes,
6481 // public visibility, etc.)
6482 if (MethodNeedsReverseComStub(pMD))
6484 // initialize ComCallMethodDesc
6485 ComCallMethodDesc ccmd;
6486 ComCallMethodDescHolder ccmdHolder(&ccmd);
6487 ccmd.InitMethod(pMD, NULL);
6489 // generate the IL stub
6491 ComCall::PopulateComCallMethodDesc(&ccmd, &dwStubFlags);
6492 pStubMD = ComCall::GetILStubMethodDesc(pMD, dwStubFlags | dwNGenStubFlags);
6494 if (pStubMD != NULL)
6496 // compile the reverse stub
6497 pStubMD = CompileMethodStubIfNeeded(pMD, pStubMD, pfnCallback, pCallbackContext);
6499 if (pStubMD != NULL)
6501 // store the stub in a hash table on the module
6502 m_image->GetModule()->GetStubMethodHashTable()->InsertMethodDesc(pMD, pStubMD);
6509 LOG((LF_ZAP, LL_WARNING, "NGEN_ILSTUB: Generating reverse interop stub FAILED: %s::%s\n", pMD->m_pszDebugClassName, pMD->m_pszDebugMethodName));
6511 EX_END_CATCH(RethrowTransientExceptions);
6512 #endif // FEATURE_COMINTEROP
6515 bool CEEPreloader::IsDynamicMethod(CORINFO_METHOD_HANDLE hMethod)
6517 STANDARD_VM_CONTRACT;
6519 MethodDesc* pMD = GetMethod(hMethod);
6523 return pMD->IsDynamicMethod();
6529 // Set method profiling flags for layout of EE datastructures
6530 void CEEPreloader::SetMethodProfilingFlags(CORINFO_METHOD_HANDLE hMethod, DWORD flags)
6532 STANDARD_VM_CONTRACT;
6534 _ASSERTE(hMethod != NULL);
6535 _ASSERTE(flags != 0);
6537 return m_image->SetMethodProfilingFlags(GetMethod(hMethod), flags);
6540 /*********************************************************************/
6541 // canSkipMethodPreparation: Is there a need for all calls from
6542 // NGEN'd code to a particular MethodDesc to go through DoPrestub,
6543 // depending on the method sematics? If so return FALSE.
6545 // This is used to rule out both ngen-hardbinds and intra-ngen-module
6548 // The cases where direct calls are not allowed are typically where
6549 // a stub must be inserted by DoPrestub (we do not save stubs) or where
6550 // we haven't saved the code for some reason or another, or where fixups
6551 // are required in the MethodDesc.
6553 // callerHnd=NULL implies any/unspecified caller.
6555 // Note that there may be other requirements for going through the prestub
6556 // which vary based on the scenario. These need to be handled separately
6558 bool CEEPreloader::CanSkipMethodPreparation (
6559 CORINFO_METHOD_HANDLE callerHnd,
6560 CORINFO_METHOD_HANDLE calleeHnd,
6561 CorInfoIndirectCallReason *pReason,
6562 CORINFO_ACCESS_FLAGS accessFlags/*=CORINFO_ACCESS_ANY*/)
6564 STANDARD_VM_CONTRACT;
6566 bool result = false;
6568 COOPERATIVE_TRANSITION_BEGIN();
6570 MethodDesc * calleeMD = (MethodDesc *)calleeHnd;
6571 MethodDesc * callerMD = (MethodDesc *)callerHnd;
6574 result = calleeMD->CanSkipDoPrestub(callerMD, pReason, accessFlags);
6577 COOPERATIVE_TRANSITION_END();
6582 CORINFO_METHOD_HANDLE CEEPreloader::LookupMethodDef(mdMethodDef token)
6584 STANDARD_VM_CONTRACT;
6585 MethodDesc *resultMD = nullptr;
6589 MethodDesc *pMD = MemberLoader::GetMethodDescFromMethodDef(m_image->GetModule(), token, FALSE);
6591 if (IsReadyToRunCompilation() && pMD->HasClassOrMethodInstantiation())
6593 _ASSERTE(IsCompilationProcess() && pMD->GetModule_NoLogging() == GetAppDomain()->ToCompilationDomain()->GetTargetModule());
6596 resultMD = pMD->FindOrCreateTypicalSharedInstantiation();
6600 this->Error(token, GET_EXCEPTION());
6602 EX_END_CATCH(SwallowAllExceptions)
6604 return CORINFO_METHOD_HANDLE(resultMD);
6607 bool CEEPreloader::GetMethodInfo(mdMethodDef token, CORINFO_METHOD_HANDLE ftnHnd, CORINFO_METHOD_INFO * methInfo)
6609 STANDARD_VM_CONTRACT;
6610 bool result = false;
6614 result = GetZapJitInfo()->getMethodInfo(ftnHnd, methInfo);
6619 this->Error(token, GET_EXCEPTION());
6621 EX_END_CATCH(SwallowAllExceptions)
6626 static BOOL MethodIsVisibleOutsideItsAssembly(DWORD dwMethodAttr)
6628 LIMITED_METHOD_CONTRACT;
6629 return (IsMdPublic(dwMethodAttr) ||
6630 IsMdFamORAssem(dwMethodAttr) ||
6631 IsMdFamily(dwMethodAttr));
6634 static BOOL ClassIsVisibleOutsideItsAssembly(DWORD dwClassAttr, BOOL fIsGlobalClass)
6636 LIMITED_METHOD_CONTRACT;
6643 return (IsTdPublic(dwClassAttr) ||
6644 IsTdNestedPublic(dwClassAttr) ||
6645 IsTdNestedFamily(dwClassAttr) ||
6646 IsTdNestedFamORAssem(dwClassAttr));
6649 static BOOL MethodIsVisibleOutsideItsAssembly(MethodDesc * pMD)
6651 LIMITED_METHOD_CONTRACT;
6653 MethodTable * pMT = pMD->GetMethodTable();
6655 if (!ClassIsVisibleOutsideItsAssembly(pMT->GetAttrClass(), pMT->IsGlobalClass()))
6658 return MethodIsVisibleOutsideItsAssembly(pMD->GetAttrs());
6661 CorCompileILRegion CEEPreloader::GetILRegion(mdMethodDef token)
6663 STANDARD_VM_CONTRACT;
6665 // Since we are running managed code during NGen the inlining hint may be
6666 // changing underneeth us as the code is JITed. We need to prevent the inlining
6667 // hints from changing once we start to use them to place IL in the image.
6668 g_pCEECompileInfo->DisableCachingOfInliningHints();
6670 // Default if there is something completely wrong, e.g. the type failed to load.
6671 // We may need the IL at runtime.
6672 CorCompileILRegion region = CORCOMPILE_ILREGION_WARM;
6676 MethodDesc *pMD = m_image->GetModule()->LookupMethodDef(token);
6678 if (pMD == NULL || !pMD->GetMethodTable()->IsFullyLoaded())
6680 // Something is completely wrong - use the default
6683 if (m_image->IsStored(pMD))
6685 if (pMD->IsNotInline())
6687 if (pMD->HasClassOrMethodInstantiation())
6689 region = CORCOMPILE_ILREGION_GENERICS;
6693 region = CORCOMPILE_ILREGION_COLD;
6697 if (MethodIsVisibleOutsideItsAssembly(pMD))
6699 // We are inlining only leaf methods, except for mscorlib. Thus we can assume that only methods
6700 // visible outside its assembly are likely to be inlined.
6701 region = CORCOMPILE_ILREGION_INLINEABLE;
6705 // We may still need the IL of the non-nonvisible methods for inlining in certain scenarios:
6706 // dynamically emitted IL, friend assemblies or JITing of generic instantiations
6707 region = CORCOMPILE_ILREGION_WARM;
6714 EX_END_CATCH(SwallowAllExceptions)
6720 CORINFO_METHOD_HANDLE CEEPreloader::FindMethodForProfileEntry(CORBBTPROF_BLOB_PARAM_SIG_ENTRY * profileBlobEntry)
6722 STANDARD_VM_CONTRACT;
6723 MethodDesc * pMethod = nullptr;
6725 _ASSERTE(profileBlobEntry->blob.type == ParamMethodSpec);
6727 if (PartialNGenStressPercentage() != 0)
6728 return CORINFO_METHOD_HANDLE( NULL );
6730 Module * pModule = GetAppDomain()->ToCompilationDomain()->GetTargetModule();
6731 pMethod = pModule->LoadIBCMethodHelper(m_image, profileBlobEntry);
6733 return CORINFO_METHOD_HANDLE( pMethod );
6736 void CEEPreloader::ReportInlining(CORINFO_METHOD_HANDLE inliner, CORINFO_METHOD_HANDLE inlinee)
6738 STANDARD_VM_CONTRACT;
6739 m_image->ReportInlining(inliner, inlinee);
6742 void CEEPreloader::Link()
6744 STANDARD_VM_CONTRACT;
6746 COOPERATIVE_TRANSITION_BEGIN();
6750 m_image->GetModule()->Save(m_image);
6751 m_image->GetModule()->Arrange(m_image);
6752 m_image->GetModule()->Fixup(m_image);
6754 m_image->PostSave();
6756 COOPERATIVE_TRANSITION_END();
6759 void CEEPreloader::FixupRVAs()
6761 STANDARD_VM_CONTRACT;
6763 COOPERATIVE_TRANSITION_BEGIN();
6765 m_image->FixupRVAs();
6767 COOPERATIVE_TRANSITION_END();
6770 void CEEPreloader::SetRVAsForFields(IMetaDataEmit * pEmit)
6772 STANDARD_VM_CONTRACT;
6774 COOPERATIVE_TRANSITION_BEGIN();
6776 m_image->SetRVAsForFields(pEmit);
6778 COOPERATIVE_TRANSITION_END();
6781 void CEEPreloader::GetRVAFieldData(mdFieldDef fd, PVOID * ppData, DWORD * pcbSize, DWORD * pcbAlignment)
6783 STANDARD_VM_CONTRACT;
6785 COOPERATIVE_TRANSITION_BEGIN();
6787 FieldDesc * pFD = m_image->GetModule()->LookupFieldDef(fd);
6789 ThrowHR(COR_E_TYPELOAD);
6791 _ASSERTE(pFD->IsRVA());
6793 UINT size = pFD->LoadSize();
6796 // Compute an alignment for the data based on the alignment
6797 // of the RVA. We'll align up to 8 bytes.
6801 DWORD rva = pFD->GetOffset();
6802 DWORD rvaTemp = rva;
6804 while ((rvaTemp&1) == 0 && align < 8 && align < size)
6811 *ppData = pFD->GetStaticAddressHandle(NULL);
6813 *pcbAlignment = align;
6815 COOPERATIVE_TRANSITION_END();
6818 ULONG CEEPreloader::Release()
6830 #ifdef FEATURE_READYTORUN_COMPILER
6831 void CEEPreloader::GetSerializedInlineTrackingMap(SBuffer* pBuffer)
6833 InlineTrackingMap * pInlineTrackingMap = m_image->GetInlineTrackingMap();
6834 PersistentInlineTrackingMapR2R::Save(m_image->GetHeap(), pBuffer, pInlineTrackingMap);
6838 void CEEPreloader::Error(mdToken token, Exception * pException)
6840 STANDARD_VM_CONTRACT;
6842 HRESULT hr = pException->GetHR();
6847 #ifdef CROSSGEN_COMPILE
6848 pException->GetMessage(msg);
6850 // Do we have an EEException with a resID?
6851 if (EEMessageException::IsEEMessageException(pException))
6853 EEMessageException * pEEMessageException = (EEMessageException *) pException;
6854 resID = pEEMessageException->GetResID();
6860 // Going though throwable gives more verbose error messages in certain cases that our tests depend on.
6861 OBJECTREF throwable = NingenEnabled() ? NULL : CLRException::GetThrowableFromException(pException);
6863 if (throwable != NULL)
6865 GetExceptionMessage(throwable, msg);
6869 pException->GetMessage(msg);
6874 m_pData->Error(token, hr, resID, msg.GetUnicode());
6877 CEEInfo *g_pCEEInfo = NULL;
6879 ICorDynamicInfo * __stdcall GetZapJitInfo()
6881 STANDARD_VM_CONTRACT;
6883 if (g_pCEEInfo == NULL)
6885 CEEInfo * p = new CEEInfo();
6886 if (InterlockedCompareExchangeT(&g_pCEEInfo, p, NULL) != NULL)
6893 CEECompileInfo *g_pCEECompileInfo = NULL;
6895 ICorCompileInfo * __stdcall GetCompileInfo()
6897 STANDARD_VM_CONTRACT;
6899 if (g_pCEECompileInfo == NULL)
6901 CEECompileInfo * p = new CEECompileInfo();
6902 if (InterlockedCompareExchangeT(&g_pCEECompileInfo, p, NULL) != NULL)
6906 return g_pCEECompileInfo;
6910 // CompilationDomain
6913 CompilationDomain::CompilationDomain(BOOL fForceDebug,
6914 BOOL fForceProfiling,
6915 BOOL fForceInstrument)
6916 : m_fForceDebug(fForceDebug),
6917 m_fForceProfiling(fForceProfiling),
6918 m_fForceInstrument(fForceInstrument),
6919 m_pTargetAssembly(NULL),
6920 m_pTargetModule(NULL),
6921 m_pTargetImage(NULL),
6923 m_pDependencyRefSpecs(NULL),
6924 m_pDependencies(NULL),
6925 m_cDependenciesCount(0),
6926 m_cDependenciesAlloc(0)
6928 STANDARD_VM_CONTRACT;
6932 void CompilationDomain::ReleaseDependencyEmitter()
6934 m_pDependencyRefSpecs.Release();
6939 CompilationDomain::~CompilationDomain()
6949 if (m_pDependencies != NULL)
6950 delete [] m_pDependencies;
6952 ReleaseDependencyEmitter();
6954 for (unsigned i = 0; i < m_rRefCaches.Size(); i++)
6956 delete m_rRefCaches[i];
6957 m_rRefCaches[i]=NULL;
6962 void CompilationDomain::Init()
6964 STANDARD_VM_CONTRACT;
6966 #ifndef CROSSGEN_COMPILE
6970 #ifndef CROSSGEN_COMPILE
6971 // allocate a Virtual Call Stub Manager for the compilation domain
6975 SetCompilationDomain();
6979 g_pConfig->DisableGenerateStubForHost();
6983 HRESULT CompilationDomain::AddDependencyEntry(PEAssembly *pFile,
6988 // This method is not multi-thread safe. This is OK because it is only called by NGen compiling, which is
6989 // effectively single-threaded. The following code verifies that we're not called on multiple threads.
6990 static volatile LONG threadId = 0;
6993 InterlockedCompareExchange(&threadId, GetCurrentThreadId(), 0);
6995 _ASSERTE((LONG)GetCurrentThreadId() == threadId);
6998 _ASSERTE((pFile == NULL) == (def == mdAssemblyRefNil));
7000 if (m_cDependenciesCount == m_cDependenciesAlloc)
7002 // Save the new count in a local variable. Can't update m_cDependenciesAlloc until the new
7003 // CORCOMPILE_DEPENDENCY array is allocated, otherwise an out-of-memory exception from new[]
7004 // operator would put the data in an inconsistent state, causing heap corruption later.
7005 USHORT cNewDependenciesAlloc = m_cDependenciesAlloc == 0 ? 20 : m_cDependenciesAlloc * 2;
7007 // Grow m_pDependencies
7009 NewArrayHolder<CORCOMPILE_DEPENDENCY> pNewDependencies(new CORCOMPILE_DEPENDENCY[cNewDependenciesAlloc]);
7011 // This block must execute transactionally. No throwing allowed. No bailing allowed.
7014 memset(pNewDependencies, 0, cNewDependenciesAlloc*sizeof(CORCOMPILE_DEPENDENCY));
7016 if (m_pDependencies)
7018 memcpy(pNewDependencies, m_pDependencies,
7019 m_cDependenciesCount*sizeof(CORCOMPILE_DEPENDENCY));
7021 delete [] m_pDependencies;
7024 m_pDependencies = pNewDependencies.Extract();
7025 m_cDependenciesAlloc = cNewDependenciesAlloc;
7029 CORCOMPILE_DEPENDENCY *pDependency = &m_pDependencies[m_cDependenciesCount++];
7031 // Clear memory so that we won't write random data into the zapped file
7032 ZeroMemory(pDependency, sizeof(CORCOMPILE_DEPENDENCY));
7034 pDependency->dwAssemblyRef = ref;
7036 pDependency->dwAssemblyDef = def;
7038 pDependency->signNativeImage = INVALID_NGEN_SIGNATURE;
7042 DomainAssembly *pAssembly = GetAppDomain()->LoadDomainAssembly(NULL, pFile, FILE_LOAD_CREATE);
7043 // Note that this can trigger an assembly load (of mscorlib)
7044 pAssembly->GetOptimizedIdentitySignature(&pDependency->signAssemblyDef);
7049 // This is done in CompilationDomain::CanEagerBindToZapFile with full support for hardbinding
7051 if (pFile->IsSystem() && pFile->HasNativeImage())
7053 CORCOMPILE_VERSION_INFO * pNativeVersion = pFile->GetLoadedNative()->GetNativeVersionInfo();
7054 pDependency->signNativeImage = pNativeVersion->signature;
7062 HRESULT CompilationDomain::AddDependency(AssemblySpec *pRefSpec,
7068 // Record the dependency
7071 // This assert prevents dependencies from silently being loaded without being recorded.
7074 // Normalize any reference to mscorlib; we don't want to record other non-canonical
7075 // mscorlib references in the ngen image since fusion doesn't understand how to bind them.
7076 // (Not to mention the fact that they are redundant.)
7078 if (pRefSpec->IsMscorlib())
7080 _ASSERTE(pFile); // mscorlib had better not be missing
7082 return E_UNEXPECTED;
7084 // Don't store a binding from mscorlib to itself.
7085 if (m_pTargetAssembly == SystemDomain::SystemAssembly())
7088 spec.InitializeSpec(pFile);
7091 else if (m_pTargetAssembly == NULL && pFile)
7093 // If target assembly is still NULL, we must be loading either the target assembly or mscorlib.
7094 // Mscorlib is already handled above, so we must be loading the target assembly if we get here.
7095 // Use the assembly name given in the target assembly so that the native image is deterministic
7096 // regardless of how the target assembly is specified on the command line.
7097 spec.InitializeSpec(pFile);
7098 if (spec.IsStrongNamed() && spec.HasPublicKey())
7100 spec.ConvertPublicKeyToToken();
7104 else if (pRefSpec->IsStrongNamed() && pRefSpec->HasPublicKey())
7106 // Normalize to always use public key token. Otherwise we may insert one reference
7107 // using public key, and another reference using public key token.
7108 spec.CopyFrom(pRefSpec);
7109 spec.ConvertPublicKeyToToken();
7113 #ifdef FEATURE_COMINTEROP
7114 // Only cache ref specs that have a unique identity. This is needed to avoid caching
7115 // things like WinRT type specs, which would benefit very little from being cached.
7116 if (!pRefSpec->HasUniqueIdentity())
7118 // Successful bind of a reference with a non-unique assembly identity.
7119 _ASSERTE(pRefSpec->IsContentType_WindowsRuntime());
7121 AssemblySpec defSpec;
7124 defSpec.InitializeSpec(pFile);
7126 // Windows Runtime Native Image binding depends on details exclusively described by the definition winmd file.
7127 // Therefore we can actually drop the existing ref spec here entirely.
7128 // Also, Windows Runtime Native Image binding uses the simple name of the ref spec as the
7129 // resolution rule for PreBind when finding definition assemblies.
7130 // See comment on CLRPrivBinderWinRT::PreBind for further details.
7131 pRefSpec = &defSpec;
7134 // Unfortunately, we don't have any choice regarding failures (pFile == NULL) because
7135 // there is no value to canonicalize on (i.e., a def spec created from a non-NULL
7136 // pFile) and so we must cache all non-unique-assembly-id failures.
7137 const AssemblySpecDefRefMapEntry * pEntry = m_dependencyDefRefMap.LookupPtr(&defSpec);
7138 if (pFile == NULL || pEntry == NULL)
7140 mdAssemblyRef refToken = mdAssemblyRefNil;
7141 IfFailRet(pRefSpec->EmitToken(m_pEmit, &refToken, TRUE, TRUE));
7143 mdAssemblyRef defToken = mdAssemblyRefNil;
7146 IfFailRet(defSpec.EmitToken(m_pEmit, &defToken, TRUE, TRUE));
7148 NewHolder<AssemblySpec> pNewDefSpec = new AssemblySpec();
7149 pNewDefSpec->CopyFrom(&defSpec);
7150 pNewDefSpec->CloneFields();
7152 NewHolder<AssemblySpec> pNewRefSpec = new AssemblySpec();
7153 pNewRefSpec->CopyFrom(pRefSpec);
7154 pNewRefSpec->CloneFields();
7156 _ASSERTE(m_dependencyDefRefMap.LookupPtr(pNewDefSpec) == NULL);
7158 AssemblySpecDefRefMapEntry e;
7159 e.m_pDef = pNewDefSpec;
7160 e.m_pRef = pNewRefSpec;
7161 m_dependencyDefRefMap.Add(e);
7163 pNewDefSpec.SuppressRelease();
7164 pNewRefSpec.SuppressRelease();
7167 IfFailRet(AddDependencyEntry(pFile, refToken, defToken));
7171 #endif // FEATURE_COMINTEROP
7174 // See if we've already added the contents of the ref
7175 // Else, emit token for the ref
7178 if (m_pDependencyRefSpecs->Store(pRefSpec))
7181 mdAssemblyRef refToken;
7182 IfFailRet(pRefSpec->EmitToken(m_pEmit, &refToken));
7185 // Make a spec for the bound assembly
7188 mdAssemblyRef defToken = mdAssemblyRefNil;
7190 // All dependencies of a shared assembly need to be shared. So for a shared
7191 // assembly, we want to remember the missing assembly ref during ngen, so that
7192 // we can probe eagerly for the dependency at load time, and make sure that
7193 // it is loaded as shared.
7194 // In such a case, pFile will be NULL
7197 AssemblySpec assemblySpec;
7198 assemblySpec.InitializeSpec(pFile);
7200 IfFailRet(assemblySpec.EmitToken(m_pEmit, &defToken));
7204 // Add the entry. Include the PEFile if we are not doing explicit bindings.
7207 IfFailRet(AddDependencyEntry(pFile, refToken, defToken));
7213 //----------------------------------------------------------------------------
7214 AssemblySpec* CompilationDomain::FindAssemblyRefSpecForDefSpec(
7215 AssemblySpec* pDefSpec)
7217 WRAPPER_NO_CONTRACT;
7219 if (pDefSpec == nullptr)
7222 const AssemblySpecDefRefMapEntry * pEntry = m_dependencyDefRefMap.LookupPtr(pDefSpec);
7223 _ASSERTE(pEntry != NULL);
7225 return (pEntry != NULL) ? pEntry->m_pRef : NULL;
7229 //----------------------------------------------------------------------------
7230 // Is it OK to embed direct pointers to an ngen dependency?
7231 // true if hardbinding is OK, false otherwise
7233 // targetModule - The pointer points into the native image of this Module.
7234 // If this native image gets relocated, the native image of
7235 // the source Module is invalidated unless the embedded
7236 // pointer can be fixed up appropriately.
7237 // limitToHardBindList - Is it OK to hard-bind to a dependency even if it is
7238 // not asked for explicitly?
7240 BOOL CompilationDomain::CanEagerBindToZapFile(Module *targetModule, BOOL limitToHardBindList)
7242 // We do this check before checking the hashtables because m_cantHardBindModules
7243 // will contain non-manifest modules. However, we do want them to be able
7244 // to hard-bind to themselves
7245 if (targetModule == m_pTargetModule)
7251 // CoreCLR does not have attributes for fine grained eager binding control.
7252 // We hard bind to mscorlib.dll only.
7254 return targetModule->IsSystem();
7258 void CompilationDomain::SetTarget(Assembly *pAssembly, Module *pModule)
7260 STANDARD_VM_CONTRACT;
7262 m_pTargetAssembly = pAssembly;
7263 m_pTargetModule = pModule;
7266 void CompilationDomain::SetTargetImage(DataImage *pImage, CEEPreloader * pPreloader)
7268 STANDARD_VM_CONTRACT;
7270 m_pTargetImage = pImage;
7271 m_pTargetPreloader = pPreloader;
7273 _ASSERTE(pImage->GetModule() == GetTargetModule());
7276 void ReportMissingDependency(Exception * e)
7278 // Avoid duplicate error messages
7279 if (FAILED(g_hrFatalError))
7285 GetSvcLogger()->Printf(LogLevel_Error, W("Error: %s\n"), s.GetUnicode());
7287 g_hrFatalError = COR_E_FILELOAD;
7290 PEAssembly *CompilationDomain::BindAssemblySpec(
7291 AssemblySpec *pSpec,
7292 BOOL fThrowOnFileNotFound,
7293 BOOL fRaisePrebindEvents,
7294 StackCrawlMark *pCallerStackMark,
7295 BOOL fUseHostBinderIfAvailable)
7297 PEAssembly *pFile = NULL;
7305 // Use normal binding rules
7306 // (possibly with our custom IApplicationContext)
7308 pFile = AppDomain::BindAssemblySpec(
7310 fThrowOnFileNotFound,
7311 fRaisePrebindEvents,
7313 fUseHostBinderIfAvailable);
7317 if (!g_fNGenMissingDependenciesOk)
7319 ReportMissingDependency(GET_EXCEPTION());
7324 // Record missing dependencies
7326 #ifdef FEATURE_COMINTEROP
7327 if (!g_fNGenWinMDResilient || pSpec->HasUniqueIdentity())
7330 IfFailThrow(AddDependency(pSpec, NULL));
7335 #ifdef FEATURE_COMINTEROP
7336 if (!g_fNGenWinMDResilient || pSpec->HasUniqueIdentity())
7339 IfFailThrow(AddDependency(pSpec, pFile));
7346 CompilationDomain::SetContextInfo(LPCWSTR path, BOOL isExe)
7348 STANDARD_VM_CONTRACT;
7352 COOPERATIVE_TRANSITION_BEGIN();
7355 COOPERATIVE_TRANSITION_END();
7360 void CompilationDomain::SetDependencyEmitter(IMetaDataAssemblyEmit *pEmit)
7362 STANDARD_VM_CONTRACT;
7367 m_pDependencyRefSpecs = new AssemblySpecHash();
7372 CompilationDomain::GetDependencies(CORCOMPILE_DEPENDENCY **ppDependencies,
7373 DWORD *pcDependencies)
7375 STANDARD_VM_CONTRACT;
7379 // Return the bindings.
7382 *ppDependencies = m_pDependencies;
7383 *pcDependencies = m_cDependenciesCount;
7385 // Cannot add any more dependencies
7386 ReleaseDependencyEmitter();
7392 #ifdef CROSSGEN_COMPILE
7393 HRESULT CompilationDomain::SetPlatformWinmdPaths(LPCWSTR pwzPlatformWinmdPaths)
7395 STANDARD_VM_CONTRACT;
7397 #ifdef FEATURE_COMINTEROP
7398 // Create the array list on the heap since it will be passed off for the Crossgen RoResolveNamespace mockup to keep for the life of the process
7399 StringArrayList *saPaths = new StringArrayList();
7401 SString strPaths(pwzPlatformWinmdPaths);
7402 if (!strPaths.IsEmpty())
7404 for (SString::Iterator i = strPaths.Begin(); i != strPaths.End(); )
7406 // Skip any leading spaces or semicolons
7407 if (strPaths.Skip(i, W(';')))
7412 SString::Iterator iEnd = i; // Where current assembly name ends
7413 SString::Iterator iNext; // Where next assembly name starts
7414 if (strPaths.Find(iEnd, W(';')))
7420 iNext = iEnd = strPaths.End();
7426 saPaths->Append(SString(strPaths, i, iEnd));
7431 Crossgen::SetFirstPartyWinMDPaths(saPaths);
7432 #endif // FEATURE_COMINTEROP
7436 #endif // CROSSGEN_COMPILE
7439 #endif // FEATURE_PREJIT