Delete FriendAccessAllowedAttribute and associated dead code (#15101)
[platform/upstream/coreclr.git] / src / vm / compile.cpp
1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4 // ===========================================================================
5 // File: compile.cpp
6 //
7
8 //
9 // Support for zap compiler and zap files 
10 // ===========================================================================
11
12
13
14 #include "common.h"
15
16 #ifdef FEATURE_PREJIT 
17
18 #include <corcompile.h>
19
20 #include "assemblyspec.hpp"
21
22 #include "compile.h"
23 #include "excep.h"
24 #include "field.h"
25 #include "eeconfig.h"
26 #include "zapsig.h"
27 #include "gcrefmap.h"
28
29
30 #include "virtualcallstub.h"
31 #include "typeparse.h"
32 #include "typestring.h"
33 #include "dllimport.h"
34 #include "comdelegate.h"
35 #include "stringarraylist.h"
36
37 #ifdef FEATURE_COMINTEROP
38 #include "clrtocomcall.h"
39 #include "comtoclrcall.h"
40 #include "winrttypenameconverter.h"
41 #endif // FEATURE_COMINTEROP
42
43 #include "dllimportcallback.h"
44 #include "caparser.h"
45 #include "sigbuilder.h"
46 #include "cgensys.h"
47 #include "peimagelayout.inl"
48
49
50 #ifdef FEATURE_COMINTEROP
51 #include "clrprivbinderwinrt.h"
52 #include "winrthelpers.h"
53 #endif
54
55 #ifdef CROSSGEN_COMPILE
56 #include "crossgenroresolvenamespace.h"
57 #endif
58
59 #ifndef NO_NGENPDB
60 #include <cvinfo.h>
61 #endif
62
63 #ifdef FEATURE_PERFMAP
64 #include "perfmap.h"
65 #endif
66
67 #include "argdestination.h"
68
69 #include "versionresilienthashcode.h"
70 #include "inlinetracking.h"
71
72 #ifdef CROSSGEN_COMPILE
73 CompilationDomain * theDomain;
74 #endif
75
76 VerboseLevel g_CorCompileVerboseLevel = CORCOMPILE_NO_LOG;
77
78 //
79 // CEECompileInfo implements most of ICorCompileInfo
80 //
81
82 HRESULT CEECompileInfo::Startup(  BOOL fForceDebug,
83                                   BOOL fForceProfiling,
84                                   BOOL fForceInstrument)
85 {
86     SystemDomain::SetCompilationOverrides(fForceDebug,
87                                           fForceProfiling,
88                                           fForceInstrument);
89
90     HRESULT hr = S_OK;
91
92     m_fCachingOfInliningHintsEnabled = TRUE;
93     m_fGeneratingNgenPDB = FALSE;
94
95     _ASSERTE(!g_fEEStarted && !g_fEEInit && "You cannot run the EE inside an NGEN compilation process");
96
97     if (!g_fEEStarted && !g_fEEInit)
98     {
99 #ifdef CROSSGEN_COMPILE
100         GetSystemInfo(&g_SystemInfo);
101
102         theDomain = new CompilationDomain(fForceDebug,
103                                           fForceProfiling,
104                                           fForceInstrument);
105 #endif
106
107         // When NGEN'ing this call may execute EE code, e.g. the managed code to set up
108         // the SharedDomain.
109         hr = InitializeEE(COINITEE_DEFAULT);
110     }
111
112     //
113     // JIT interface expects to be called with
114     // preemptive GC enabled
115     //
116     if (SUCCEEDED(hr)) {
117 #ifdef _DEBUG
118         Thread *pThread = GetThread();
119         _ASSERTE(pThread);
120 #endif
121
122         GCX_PREEMP_NO_DTOR();
123     }
124
125     return hr;
126 }
127
128 HRESULT CEECompileInfo::CreateDomain(ICorCompilationDomain **ppDomain,
129                                      IMetaDataAssemblyEmit *pEmitter,
130                                      BOOL fForceDebug,
131                                      BOOL fForceProfiling,
132                                      BOOL fForceInstrument,
133                                      BOOL fForceFulltrustDomain)
134 {
135     STANDARD_VM_CONTRACT;
136
137     COOPERATIVE_TRANSITION_BEGIN();
138
139 #ifndef CROSSGEN_COMPILE
140     AppDomainCreationHolder<CompilationDomain> pCompilationDomain;
141
142     pCompilationDomain.Assign(new CompilationDomain(fForceDebug,
143                                                     fForceProfiling,
144                                                     fForceInstrument));
145 #else
146     CompilationDomain * pCompilationDomain = theDomain;
147 #endif
148
149     {
150         SystemDomain::LockHolder lh;
151         pCompilationDomain->Init();
152     }
153
154     if (pEmitter)
155         pCompilationDomain->SetDependencyEmitter(pEmitter);
156     
157
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
163     
164     pCompilationDomain->LoadSystemAssemblies();
165     
166     pCompilationDomain->SetupSharedStatics();
167     
168     *ppDomain = static_cast<ICorCompilationDomain*>(pCompilationDomain);
169     
170     {
171         GCX_COOP();
172
173         ENTER_DOMAIN_PTR(pCompilationDomain,ADV_COMPILATION)
174         {
175             pCompilationDomain->InitializeDomainContext(TRUE, NULL, NULL);
176
177             pCompilationDomain->SetFriendlyName(W("Compilation Domain"));
178             SystemDomain::System()->LoadDomain(pCompilationDomain);
179
180 #ifndef CROSSGEN_COMPILE
181             pCompilationDomain.DoneCreating();
182 #endif
183         }
184         END_DOMAIN_TRANSITION;
185     }
186
187     COOPERATIVE_TRANSITION_END();
188
189     return S_OK;
190 }
191
192
193 HRESULT CEECompileInfo::DestroyDomain(ICorCompilationDomain *pDomain)
194 {
195     STANDARD_VM_CONTRACT;
196
197 #ifndef CROSSGEN_COMPILE
198     COOPERATIVE_TRANSITION_BEGIN();
199
200     GCX_COOP();
201
202     CompilationDomain *pCompilationDomain = (CompilationDomain *) pDomain;
203
204     // DDB 175659: Make sure that canCallNeedsRestore() returns FALSE during compilation 
205     // domain shutdown.
206     pCompilationDomain->setCannotCallNeedsRestore();
207
208     pCompilationDomain->Unload(TRUE);
209
210     COOPERATIVE_TRANSITION_END();
211 #endif
212
213     return S_OK;
214 }
215
216 HRESULT MakeCrossDomainCallbackWorker(
217     CROSS_DOMAIN_CALLBACK   pfnCallback,
218     LPVOID                  pArgs)
219 {
220     STATIC_CONTRACT_MODE_COOPERATIVE;
221     STATIC_CONTRACT_SO_INTOLERANT;
222
223     HRESULT hrRetVal = E_UNEXPECTED;
224     BEGIN_SO_TOLERANT_CODE(GetThread());
225     hrRetVal = pfnCallback(pArgs);
226     END_SO_TOLERANT_CODE;
227     return hrRetVal;
228 }
229
230 HRESULT CEECompileInfo::MakeCrossDomainCallback(
231     ICorCompilationDomain*  pDomain,
232     CROSS_DOMAIN_CALLBACK   pfnCallback,
233     LPVOID                  pArgs)
234 {
235     STANDARD_VM_CONTRACT;
236
237     HRESULT hrRetVal = E_UNEXPECTED;
238
239     COOPERATIVE_TRANSITION_BEGIN();
240
241     {
242         // Switch to cooperative mode to switch appdomains
243         GCX_COOP();
244
245         ENTER_DOMAIN_PTR((CompilationDomain*)pDomain,ADV_COMPILATION)
246         {
247             //
248             // Switch to preemptive mode on before calling back into
249             // the zapper
250             //
251             
252             GCX_PREEMP();
253             
254             hrRetVal = MakeCrossDomainCallbackWorker(pfnCallback, pArgs);
255         }
256         END_DOMAIN_TRANSITION;
257     }
258
259     COOPERATIVE_TRANSITION_END();
260
261     return hrRetVal;
262 }
263
264 #ifdef TRITON_STRESS_NEED_IMPL
265 int LogToSvcLogger(LPCWSTR format, ...)
266 {
267     STANDARD_VM_CONTRACT;
268
269     StackSString s;
270
271     va_list args;
272     va_start(args, format);
273     s.VPrintf(format, args);
274     va_end(args);
275
276     GetSvcLogger()->Printf(W("%s"), s.GetUnicode());
277
278     return 0;
279 }
280 #endif
281
282 HRESULT CEECompileInfo::LoadAssemblyByPath(
283     LPCWSTR                  wzPath,
284     
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,
288
289     CORINFO_ASSEMBLY_HANDLE *pHandle)
290 {
291     STANDARD_VM_CONTRACT;
292
293     HRESULT hr = S_OK;
294
295     COOPERATIVE_TRANSITION_BEGIN();
296
297     Assembly * pAssembly;
298     HRESULT    hrProcessLibraryBitnessMismatch = S_OK;
299
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.
302
303     EX_TRY
304     {
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.
307
308         PEImageHolder pImage;
309
310
311         if (pImage == NULL)
312         {
313             pImage = PEImage::OpenImage(
314                 wzPath,
315
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);
321         }
322
323         if (fExplicitBindToNativeImage && !pImage->HasReadyToRunHeader())
324         {
325             pImage->VerifyIsNIAssembly();
326         }
327         else
328         {
329             pImage->VerifyIsAssembly();
330         }
331
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
337 #ifdef _WIN64
338         if (pImage->Has32BitNTHeaders())
339         {
340             hrProcessLibraryBitnessMismatch = PEFMT_E_32BIT;
341         }
342 #else
343         if (!pImage->Has32BitNTHeaders())
344         {
345             hrProcessLibraryBitnessMismatch = PEFMT_E_64BIT;
346         }
347 #endif
348         
349         AssemblySpec spec;
350         spec.InitializeSpec(TokenFromRid(1, mdtAssembly), pImage->GetMDImport(), NULL, FALSE);
351
352         if (spec.IsMscorlib())
353         {
354             pAssembly = SystemDomain::System()->SystemAssembly();
355         }
356         else
357         {
358             AppDomain * pDomain = AppDomain::GetCurrentDomain();
359
360             PEAssemblyHolder pAssemblyHolder;
361             BOOL isWinRT = FALSE;
362
363 #ifdef FEATURE_COMINTEROP
364             isWinRT = spec.IsContentType_WindowsRuntime();
365             if (isWinRT)
366             {
367                 LPCSTR  szNameSpace;
368                 LPCSTR  szTypeName;
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);
375             }
376 #endif //FEATURE_COMINTEROP
377
378             // If there is a host binder then use it to bind the assembly.
379             if (pDomain->HasLoadContextHostBinder() || isWinRT)
380             {
381                 pAssemblyHolder = pDomain->BindAssemblySpec(&spec, TRUE, FALSE);
382             }
383             else
384             {
385                 //ExplicitBind
386                 CoreBindResult bindResult;
387                 spec.SetCodeBase(pImage->GetPath());
388                 spec.Bind(
389                     pDomain,
390                     TRUE,                   // fThrowOnFileNotFound
391                     &bindResult, 
392
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
399                     // open an NI).
400                     !fExplicitBindToNativeImage,
401
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
406                     );
407                 pAssemblyHolder = PEAssembly::Open(&bindResult,FALSE,FALSE);
408             }
409
410             // Now load assembly into domain.
411             DomainAssembly * pDomainAssembly = pDomain->LoadDomainAssembly(&spec, pAssemblyHolder, FILE_LOAD_BEGIN);
412
413             if (spec.CanUseWithBindingCache() && pDomainAssembly->CanUseWithBindingCache())
414                 pDomain->AddAssemblyToCache(&spec, pDomainAssembly);
415
416
417             {
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();
421             }
422
423             pAssembly = pDomain->LoadAssembly(&spec, pAssemblyHolder, FILE_LOADED);
424
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);
429         }
430
431         // Kind of a workaround - if we could have loaded this assembly via normal load,
432
433         *pHandle = CORINFO_ASSEMBLY_HANDLE(pAssembly);
434     }
435     EX_CATCH_HRESULT(hr);
436     
437     if ( hrProcessLibraryBitnessMismatch != S_OK && ( hr == COR_E_BADIMAGEFORMAT || hr == HRESULT_FROM_WIN32(ERROR_BAD_EXE_FORMAT) ) )
438     {
439         hr = hrProcessLibraryBitnessMismatch;
440     }
441     
442     COOPERATIVE_TRANSITION_END();
443
444     return hr;
445 }
446
447
448 #ifdef FEATURE_COMINTEROP
449 HRESULT CEECompileInfo::LoadTypeRefWinRT(
450     IMDInternalImport       *pAssemblyImport,
451     mdTypeRef               ref,
452     CORINFO_ASSEMBLY_HANDLE *pHandle)
453 {
454     STANDARD_VM_CONTRACT;
455
456     HRESULT hr = S_OK;
457
458     ReleaseHolder<IAssemblyName> pAssemblyName;
459
460     COOPERATIVE_TRANSITION_BEGIN();
461     
462     EX_TRY
463     {
464         Assembly *pAssembly;
465
466         mdToken tkResolutionScope;
467         if(FAILED(pAssemblyImport->GetResolutionScopeOfTypeRef(ref, &tkResolutionScope)))
468             hr = S_FALSE;
469         else if(TypeFromToken(tkResolutionScope) == mdtAssemblyRef)
470         {
471             DWORD dwAssemblyRefFlags;
472             IfFailThrow(pAssemblyImport->GetAssemblyRefProps(tkResolutionScope, NULL, NULL,
473                                                      NULL, NULL,
474                                                      NULL, NULL, &dwAssemblyRefFlags));
475             if (IsAfContentType_WindowsRuntime(dwAssemblyRefFlags))
476             {
477                 LPCSTR psznamespace;
478                 LPCSTR pszname;
479                 pAssemblyImport->GetNameOfTypeRef(ref, &psznamespace, &pszname);
480                 AssemblySpec spec;
481                 spec.InitializeSpec(tkResolutionScope, pAssemblyImport, NULL, FALSE);
482                 spec.SetWindowsRuntimeType(psznamespace, pszname);
483                 
484                 _ASSERTE(spec.HasBindableIdentity());
485                 
486                 pAssembly = spec.LoadAssembly(FILE_LOADED);
487
488                 //
489                 // Return the module handle
490                 //
491
492                 *pHandle = CORINFO_ASSEMBLY_HANDLE(pAssembly);
493             }
494             else
495             {
496                 hr = S_FALSE;
497             }
498         }
499         else
500         {
501             hr = S_FALSE;
502         }
503     }
504     EX_CATCH_HRESULT(hr);
505
506     COOPERATIVE_TRANSITION_END();
507
508     return hr;
509 }
510 #endif
511
512 BOOL CEECompileInfo::IsInCurrentVersionBubble(CORINFO_MODULE_HANDLE hModule)
513 {
514     WRAPPER_NO_CONTRACT;
515
516     return ((Module*)hModule)->IsInCurrentVersionBubble();
517 }
518
519 HRESULT CEECompileInfo::LoadAssemblyModule(
520     CORINFO_ASSEMBLY_HANDLE assembly,
521     mdFile                  file,
522     CORINFO_MODULE_HANDLE   *pHandle)
523 {
524     STANDARD_VM_CONTRACT;
525
526     COOPERATIVE_TRANSITION_BEGIN();
527
528     Assembly *pAssembly = (Assembly*) assembly;
529
530     Module *pModule = pAssembly->GetManifestModule()->LoadModule(GetAppDomain(), file, TRUE)->GetModule();
531
532     //
533     // Return the module handle
534     //
535
536     *pHandle = CORINFO_MODULE_HANDLE(pModule);
537
538     COOPERATIVE_TRANSITION_END();
539
540     return S_OK;
541 }
542
543
544 BOOL CEECompileInfo::CheckAssemblyZap(
545     CORINFO_ASSEMBLY_HANDLE assembly, 
546   __out_ecount_opt(*cAssemblyManifestModulePath) 
547     LPWSTR                  assemblyManifestModulePath, 
548     LPDWORD                 cAssemblyManifestModulePath)
549 {
550     STANDARD_VM_CONTRACT;
551
552     BOOL result = FALSE;
553
554     COOPERATIVE_TRANSITION_BEGIN();
555
556     Assembly *pAssembly = (Assembly*) assembly;
557
558     if (pAssembly->GetManifestFile()->HasNativeImage())
559     {
560         PEImage *pImage = pAssembly->GetManifestFile()->GetPersistentNativeImage();
561
562         if (assemblyManifestModulePath != NULL)
563         {
564             DWORD length = pImage->GetPath().GetCount();
565             if (length > *cAssemblyManifestModulePath)
566             {
567                 length = *cAssemblyManifestModulePath - 1;
568                 wcsncpy_s(assemblyManifestModulePath, *cAssemblyManifestModulePath, pImage->GetPath(), length);
569                 assemblyManifestModulePath[length] = 0;
570             }
571             else
572                 wcscpy_s(assemblyManifestModulePath, *cAssemblyManifestModulePath, pImage->GetPath());
573         }
574
575         result = TRUE;
576     }
577
578     COOPERATIVE_TRANSITION_END();
579
580     return result;
581 }
582
583 HRESULT CEECompileInfo::SetCompilationTarget(CORINFO_ASSEMBLY_HANDLE     assembly,
584                                              CORINFO_MODULE_HANDLE       module)
585 {
586     STANDARD_VM_CONTRACT;
587
588     Assembly *pAssembly = (Assembly *) assembly;
589     Module *pModule = (Module *) module;
590
591     CompilationDomain *pDomain = (CompilationDomain *) GetAppDomain();
592     pDomain->SetTarget(pAssembly, pModule);
593
594     if (!pAssembly->IsSystem())
595     {
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.
599
600         AssemblySpec mscorlib;
601         mscorlib.InitializeSpec(SystemDomain::SystemFile());
602         GetAppDomain()->BindAssemblySpec(&mscorlib,TRUE,FALSE);
603
604         if (!IsReadyToRunCompilation() && !SystemDomain::SystemFile()->HasNativeImage())
605         {
606             if (!CLRConfig::GetConfigValue(CLRConfig::INTERNAL_NgenAllowMscorlibSoftbind))
607             {
608                 return NGEN_E_SYS_ASM_NI_MISSING;
609             }
610         }
611     }
612
613     return S_OK;
614 }
615
616 IMDInternalImport *
617     CEECompileInfo::GetAssemblyMetaDataImport(CORINFO_ASSEMBLY_HANDLE assembly)
618 {
619     STANDARD_VM_CONTRACT;
620
621     IMDInternalImport * import;
622
623     COOPERATIVE_TRANSITION_BEGIN();
624
625     import = ((Assembly*)assembly)->GetManifestImport();
626     import->AddRef();
627
628     COOPERATIVE_TRANSITION_END();
629
630     return import;
631 }
632
633 IMDInternalImport *
634     CEECompileInfo::GetModuleMetaDataImport(CORINFO_MODULE_HANDLE scope)
635 {
636     STANDARD_VM_CONTRACT;
637
638     IMDInternalImport * import;
639
640     COOPERATIVE_TRANSITION_BEGIN();
641
642     import = ((Module*)scope)->GetMDImport();
643     import->AddRef();
644
645     COOPERATIVE_TRANSITION_END();
646
647     return import;
648 }
649
650 CORINFO_MODULE_HANDLE
651     CEECompileInfo::GetAssemblyModule(CORINFO_ASSEMBLY_HANDLE assembly)
652 {
653     STANDARD_VM_CONTRACT;
654
655     CANNOTTHROWCOMPLUSEXCEPTION();
656
657     return (CORINFO_MODULE_HANDLE) ((Assembly*)assembly)->GetManifestModule();
658 }
659
660 PEDecoder * CEECompileInfo::GetModuleDecoder(CORINFO_MODULE_HANDLE scope)
661 {
662     STANDARD_VM_CONTRACT;
663
664     PEDecoder *result;
665
666     COOPERATIVE_TRANSITION_BEGIN();
667
668     //
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.
673     //
674
675     PEFile *pFile = ((Module *) scope)->GetFile();
676
677     if (pFile->HasNativeImage())
678         result = pFile->GetLoadedNative();
679     else
680         result = pFile->GetLoadedIL();
681
682     COOPERATIVE_TRANSITION_END();
683
684     return result;
685
686 }
687
688 void CEECompileInfo::GetModuleFileName(CORINFO_MODULE_HANDLE scope,
689                                        SString               &result)
690 {
691     STANDARD_VM_CONTRACT;
692
693     COOPERATIVE_TRANSITION_BEGIN();
694
695     result.Set(((Module*)scope)->GetPath());
696
697     COOPERATIVE_TRANSITION_END();
698 }
699
700 CORINFO_ASSEMBLY_HANDLE
701     CEECompileInfo::GetModuleAssembly(CORINFO_MODULE_HANDLE module)
702 {
703     STANDARD_VM_CONTRACT;
704
705     CANNOTTHROWCOMPLUSEXCEPTION();
706
707     return (CORINFO_ASSEMBLY_HANDLE) GetModule(module)->GetAssembly();
708 }
709
710
711 #ifdef CROSSGEN_COMPILE
712 //
713 // Small wrapper to avoid having too many crossgen ifdefs
714 //
715 class AssemblyForLoadHint
716 {
717     IMDInternalImport * m_pMDImport;
718 public:
719     AssemblyForLoadHint(IMDInternalImport * pMDImport)
720         : m_pMDImport(pMDImport)
721     {
722     }
723
724     IMDInternalImport * GetManifestImport()
725     {
726         return m_pMDImport;
727     }
728
729     LPCSTR GetSimpleName()
730     {
731         LPCSTR name = "";
732         IfFailThrow(m_pMDImport->GetAssemblyProps(TokenFromRid(1, mdtAssembly), NULL, NULL, NULL, &name, NULL, NULL));
733         return name;
734     }
735
736     void GetDisplayName(SString &result, DWORD flags = 0)
737     {
738         PEAssembly::GetFullyQualifiedAssemblyName(m_pMDImport, TokenFromRid(1, mdtAssembly), result, flags);
739     }
740
741     BOOL IsSystem()
742     {
743         return FALSE;
744     }
745 };
746 #endif
747
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)
758 {
759     STANDARD_VM_CONTRACT;
760
761     // First, check for this:
762     //    DependencyAttribute("Foo", LoadHint.Always)
763     StackSString simpleName(SString::Utf8, pAssembly->GetSimpleName());
764     if (simpleName.EqualsCaseInsensitive(dependencyNameFromCA, PEImage::GetFileSystemLocale()))
765         return TRUE;
766
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()))
772         return TRUE;
773
774     // Finally:
775     //    DependencyAttribute("Foo, Version=2.0.0.0, Culture=neutral", LoadHint.Always)
776     StackSString fullName;
777     pAssembly->GetDisplayName(fullName);
778     if (fullName.EqualsCaseInsensitive(dependencyNameFromCA))
779         return TRUE;
780
781     return FALSE;
782 }
783
784 template <typename ASSEMBLY>
785 void GetLoadHint(ASSEMBLY * pAssembly, ASSEMBLY *pAssemblyDependency,
786                  LoadHintEnum *loadHint, LoadHintEnum *defaultLoadHint = NULL)
787 {
788     STANDARD_VM_CONTRACT;
789
790     *loadHint = LoadDefault;
791
792     if (g_pConfig->NgenHardBind() == EEConfig::NGEN_HARD_BIND_ALL)
793         *loadHint = LoadAlways;
794
795     const BYTE  *pbAttr;                // Custom attribute data as a BYTE*.
796     ULONG       cbAttr;                 // Size of custom attribute data.
797     mdToken     mdAssembly;
798
799     // Look for the binding custom attribute
800     {
801         IMDInternalImport *pImport = pAssembly->GetManifestImport();
802
803         IfFailThrow(pImport->GetAssemblyFromScope(&mdAssembly));
804
805         MDEnumHolder hEnum(pImport);        // Enumerator for custom attributes
806         IfFailThrow(pImport->EnumCustomAttributeByNameInit(mdAssembly, DEPENDENCY_TYPE, &hEnum));
807
808         mdCustomAttribute tkAttribute;      // A custom attribute on this assembly.
809         while (pImport->EnumNext(&hEnum, &tkAttribute))
810         {
811             // Get raw custom attribute.
812             IfFailThrow(pImport->GetCustomAttributeAsBlob(tkAttribute, (const void**)&pbAttr, &cbAttr));
813
814             CustomAttributeParser cap(pbAttr, cbAttr);
815
816             IfFailThrow(cap.ValidateProlog());
817
818             // Extract string from custom attribute
819             LPCUTF8 szString;
820             ULONG   cbString;
821             IfFailThrow(cap.GetNonNullString(&szString, &cbString));
822
823             // Convert the string to Unicode.
824             StackSString dependencyNameFromCA(SString::Utf8, szString, cbString);
825
826             if (IsAssemblySpecifiedInCA(pAssemblyDependency, dependencyNameFromCA))
827             {
828                 // Get dependency setting
829                 UINT32 u4;
830                 IfFailThrow(cap.GetU4(&u4));
831                 *loadHint = (LoadHintEnum)u4;
832                 break;
833             }
834         }
835     }
836
837     // If not preference is specified, look for the built-in assembly preference
838     if (*loadHint == LoadDefault || defaultLoadHint != NULL)
839     {
840         IMDInternalImport *pImportDependency = pAssemblyDependency->GetManifestImport();
841
842         IfFailThrow(pImportDependency->GetAssemblyFromScope(&mdAssembly));
843
844         HRESULT hr = pImportDependency->GetCustomAttributeByName(mdAssembly,
845             DEFAULTDEPENDENCY_TYPE,
846             (const void**)&pbAttr, &cbAttr);
847         IfFailThrow(hr);
848
849         // Parse the attribute
850         if (hr == S_OK)
851         {
852             CustomAttributeParser cap(pbAttr, cbAttr);
853             IfFailThrow(cap.ValidateProlog());
854
855             // Get default bind setting
856             UINT32 u4 = 0;
857             IfFailThrow(cap.GetU4(&u4));
858
859             if (pAssemblyDependency->IsSystem() && CLRConfig::GetConfigValue(CLRConfig::INTERNAL_NgenAllowMscorlibSoftbind))
860             {
861                 u4 = LoadDefault;
862             }
863
864             if (defaultLoadHint)
865                 *defaultLoadHint = (LoadHintEnum) u4;
866             else
867                 *loadHint = (LoadHintEnum) u4;
868         }
869     }
870 }
871
872 HRESULT CEECompileInfo::GetLoadHint(CORINFO_ASSEMBLY_HANDLE hAssembly,
873                                     CORINFO_ASSEMBLY_HANDLE hAssemblyDependency,
874                                     LoadHintEnum *loadHint,
875                                     LoadHintEnum *defaultLoadHint)
876 {
877     STANDARD_VM_CONTRACT;
878
879     HRESULT hr = S_OK;
880
881     EX_TRY
882     {
883         Assembly *pAssembly           = (Assembly *) hAssembly;
884         Assembly *pAssemblyDependency = (Assembly *) hAssemblyDependency;
885
886         ::GetLoadHint(pAssembly, pAssemblyDependency, loadHint, defaultLoadHint);
887     }
888     EX_CATCH_HRESULT(hr);
889
890     return hr;
891 }
892
893 HRESULT CEECompileInfo::GetAssemblyVersionInfo(CORINFO_ASSEMBLY_HANDLE hAssembly,
894                                                CORCOMPILE_VERSION_INFO *pInfo)
895 {
896     STANDARD_VM_CONTRACT;
897
898     Assembly *pAssembly = (Assembly *) hAssembly;
899
900     pAssembly->GetDomainAssembly()->GetCurrentVersionInfo(pInfo);
901
902     return S_OK;
903 }
904
905 void CEECompileInfo::GetAssemblyCodeBase(CORINFO_ASSEMBLY_HANDLE hAssembly, SString &result)
906 {
907     STANDARD_VM_CONTRACT;
908
909     COOPERATIVE_TRANSITION_BEGIN();
910
911     Assembly *pAssembly = (Assembly *)hAssembly;
912     _ASSERTE(pAssembly != NULL);
913
914     pAssembly->GetCodeBase(result);
915
916     COOPERATIVE_TRANSITION_END();
917 }
918
919 //=================================================================================
920
921 void FakePromote(PTR_PTR_Object ppObj, ScanContext *pSC, uint32_t dwFlags)
922 {
923     CONTRACTL {
924         NOTHROW;
925         GC_NOTRIGGER;
926         MODE_ANY;
927     } CONTRACTL_END;
928
929     _ASSERTE(*ppObj == NULL);
930     *(CORCOMPILE_GCREFMAP_TOKENS *)ppObj = (dwFlags & GC_CALL_INTERIOR) ? GCREFMAP_INTERIOR : GCREFMAP_REF;
931 }
932
933 //=================================================================================
934
935 void FakePromoteCarefully(promote_func *fn, Object **ppObj, ScanContext *pSC, uint32_t dwFlags)
936 {
937     (*fn)(ppObj, pSC, dwFlags);
938 }
939
940 //=================================================================================
941
942 void FakeGcScanRoots(MetaSig& msig, ArgIterator& argit, MethodDesc * pMD, BYTE * pFrame)
943 {
944     STANDARD_VM_CONTRACT;
945
946     ScanContext sc;
947
948     // Encode generic instantiation arg
949     if (argit.HasParamType())
950     {
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;
954         else 
955         if (pMD->RequiresInstMethodTableArg())
956             *(CORCOMPILE_GCREFMAP_TOKENS *)(pFrame + argit.GetParamTypeArgOffset()) = GCREFMAP_TYPE_PARAM;
957     }
958
959     // If the function has a this pointer, add it to the mask
960     if (argit.HasThis())
961     {
962         BOOL interior = pMD->GetMethodTable()->IsValueType() && !pMD->IsUnboxingStub();
963
964         FakePromote((Object **)(pFrame + argit.GetThisOffset()), &sc, interior ? GC_CALL_INTERIOR : 0);
965     }
966
967     if (argit.IsVarArg())
968     {
969         *(CORCOMPILE_GCREFMAP_TOKENS *)(pFrame + argit.GetVASigCookieOffset()) = GCREFMAP_VASIG_COOKIE;
970
971         // We are done for varargs - the remaining arguments are reported via vasig cookie
972         return;
973     }
974
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())
978     {
979         FakePromote((Object **)(pFrame + argit.GetRetBuffArgOffset()), &sc, GC_CALL_INTERIOR);
980     }
981
982     //
983     // Now iterate the arguments
984     //
985
986     // Cycle through the arguments, and call msig.GcScanRoots for each
987     int argOffset;
988     while ((argOffset = argit.GetNextOffset()) != TransitionBlock::InvalidOffset)
989     {
990         ArgDestination argDest(pFrame, argOffset, argit.GetArgLocDescForStructInRegs());
991         msig.GcScanRoots(&argDest, &FakePromote, &sc, &FakePromoteCarefully);
992     }
993 }
994
995 void CEECompileInfo::GetCallRefMap(CORINFO_METHOD_HANDLE hMethod, GCRefMapBuilder * pBuilder)
996 {
997 #ifdef _DEBUG
998     DWORD dwInitialLength = pBuilder->GetBlobLength();
999     UINT nTokensWritten = 0;
1000 #endif
1001
1002     MethodDesc *pMD = (MethodDesc *)hMethod;
1003
1004     MetaSig msig(pMD);
1005     ArgIterator argit(&msig);
1006
1007     UINT nStackBytes = argit.SizeOfFrameArgumentArray();
1008
1009     // Allocate a fake stack
1010     CQuickBytes qbFakeStack;
1011     qbFakeStack.AllocThrows(sizeof(TransitionBlock) + nStackBytes);
1012     memset(qbFakeStack.Ptr(), 0, qbFakeStack.Size());
1013
1014     BYTE * pFrame = (BYTE *)qbFakeStack.Ptr();
1015
1016     // Fill it in
1017     FakeGcScanRoots(msig, argit, pMD, pFrame);
1018
1019     //
1020     // Encode the ref map
1021     //
1022
1023     UINT nStackSlots;
1024
1025 #ifdef _TARGET_X86_
1026     UINT cbStackPop = argit.CbStackPop();
1027     pBuilder->WriteStackPop(cbStackPop / sizeof(TADDR));
1028
1029     nStackSlots = nStackBytes / sizeof(TADDR) + NUM_ARGUMENT_REGISTERS;
1030 #else
1031     nStackSlots = (sizeof(TransitionBlock) + nStackBytes - TransitionBlock::GetOffsetOfArgumentRegisters()) / sizeof(TADDR);
1032 #endif
1033
1034     for (UINT pos = 0; pos < nStackSlots; pos++)
1035     {
1036         int ofs;
1037
1038 #ifdef _TARGET_X86_
1039         ofs = (pos < NUM_ARGUMENT_REGISTERS) ?
1040             (TransitionBlock::GetOffsetOfArgumentRegisters() + ARGUMENTREGISTERS_SIZE - (pos + 1) * sizeof(TADDR)) :
1041             (TransitionBlock::GetOffsetOfArgs() + (pos - NUM_ARGUMENT_REGISTERS) * sizeof(TADDR));
1042 #else
1043         ofs = TransitionBlock::GetOffsetOfArgumentRegisters() + pos * sizeof(TADDR);
1044 #endif
1045
1046         CORCOMPILE_GCREFMAP_TOKENS token = *(CORCOMPILE_GCREFMAP_TOKENS *)(pFrame + ofs);
1047
1048         if (token != 0)
1049         {
1050             INDEBUG(nTokensWritten++;)
1051             pBuilder->WriteToken(pos, token);
1052         }
1053     }
1054
1055     // We are done
1056     pBuilder->Flush();
1057
1058 #ifdef _DEBUG
1059     //
1060     // Verify that decoder produces what got encoded
1061     //
1062
1063     DWORD dwFinalLength;
1064     PVOID pBlob = pBuilder->GetBlob(&dwFinalLength);
1065
1066     UINT nTokensDecoded = 0;
1067
1068     GCRefMapDecoder decoder((BYTE *)pBlob + dwInitialLength);
1069
1070 #ifdef _TARGET_X86_
1071     _ASSERTE(decoder.ReadStackPop() * sizeof(TADDR) == cbStackPop);
1072 #endif
1073
1074     while (!decoder.AtEnd())
1075     {
1076         int pos = decoder.CurrentPos();
1077         int token = decoder.ReadToken();
1078
1079         int ofs;
1080
1081 #ifdef _TARGET_X86_
1082         ofs = (pos < NUM_ARGUMENT_REGISTERS) ?
1083             (TransitionBlock::GetOffsetOfArgumentRegisters() + ARGUMENTREGISTERS_SIZE - (pos + 1) * sizeof(TADDR)) :
1084             (TransitionBlock::GetOffsetOfArgs() + (pos - NUM_ARGUMENT_REGISTERS) * sizeof(TADDR));
1085 #else
1086         ofs = TransitionBlock::GetOffsetOfArgumentRegisters() + pos * sizeof(TADDR);
1087 #endif
1088
1089         if (token != 0)
1090         {
1091             _ASSERTE(*(CORCOMPILE_GCREFMAP_TOKENS *)(pFrame + ofs) == token);
1092             nTokensDecoded++;
1093         }
1094     }
1095
1096     // Verify that all tokens got decoded.
1097     _ASSERTE(nTokensWritten == nTokensDecoded);
1098 #endif // _DEBUG
1099 }
1100
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
1107     )
1108 {
1109     STANDARD_VM_CONTRACT;
1110
1111     CompressDebugInfo::CompressBoundariesAndVars(pOffsetMapping, iOffsetMapping, pNativeVarInfo, iNativeVarInfo, pDebugInfoBuffer, NULL);
1112 }
1113
1114 HRESULT CEECompileInfo::GetBaseJitFlags(
1115         IN  CORINFO_METHOD_HANDLE   hMethod,
1116         OUT CORJIT_FLAGS           *pFlags)
1117 {
1118     STANDARD_VM_CONTRACT;
1119
1120     MethodDesc *pMD = (MethodDesc *)hMethod;
1121     *pFlags = CEEInfo::GetBaseCompileFlags(pMD);
1122
1123     return S_OK;
1124 }
1125
1126 //=================================================================================
1127
1128 #ifdef _DEBUG 
1129
1130 static struct
1131 {
1132     size_t total;
1133     size_t noEmbed;
1134     size_t array;
1135     size_t primitives;
1136     size_t szarray;
1137 } embedStats;
1138
1139 #endif // _DEBUG
1140
1141 BOOL CEEPreloader::CanEmbedClassID(CORINFO_CLASS_HANDLE    typeHandle)
1142 {
1143     STANDARD_VM_CONTRACT;
1144
1145     TypeHandle hnd = (TypeHandle) typeHandle;
1146     return m_image->CanEagerBindToTypeHandle(hnd) && 
1147         !hnd.AsMethodTable()->NeedsCrossModuleGenericsStaticsInfo();
1148 }
1149
1150 BOOL CEEPreloader::CanEmbedModuleID(CORINFO_MODULE_HANDLE    moduleHandle)
1151 {
1152     STANDARD_VM_CONTRACT;
1153
1154     return m_image->CanEagerBindToModule((Module *)moduleHandle);
1155 }
1156
1157 BOOL CEEPreloader::CanEmbedModuleHandle(CORINFO_MODULE_HANDLE    moduleHandle)
1158 {
1159     STANDARD_VM_CONTRACT;
1160
1161     return m_image->CanEagerBindToModule((Module *)moduleHandle);
1162
1163 }
1164 BOOL CEEPreloader::CanEmbedClassHandle(CORINFO_CLASS_HANDLE    typeHandle)
1165 {
1166     STANDARD_VM_CONTRACT;
1167
1168     TypeHandle hnd = (TypeHandle) typeHandle;
1169
1170     BOOL decision = m_image->CanEagerBindToTypeHandle(hnd);
1171
1172 #ifdef _DEBUG 
1173     embedStats.total++;
1174
1175     if (!decision)
1176         embedStats.noEmbed++;
1177
1178     if (hnd.IsArray())
1179     {
1180         embedStats.array++;
1181
1182         CorElementType arrType = hnd.AsArray()->GetInternalCorElementType();
1183         if (arrType == ELEMENT_TYPE_SZARRAY)
1184             embedStats.szarray++;
1185
1186         CorElementType elemType = hnd.AsArray()->GetArrayElementTypeHandle().GetInternalCorElementType();
1187         if (elemType <= ELEMENT_TYPE_R8)
1188             embedStats.primitives++;
1189     }
1190 #endif // _DEBUG
1191     return decision;
1192 }
1193
1194
1195 /*static*/ BOOL CanEmbedMethodDescViaContext(MethodDesc * pMethod, MethodDesc * pContext)
1196 {
1197     STANDARD_VM_CONTRACT;
1198
1199     if (pContext != NULL)
1200     {
1201         _ASSERTE(pContext->GetLoaderModule() == GetAppDomain()->ToCompilationDomain()->GetTargetModule());
1202
1203         // a method can always embed its own handle
1204         if (pContext == pMethod)
1205         {
1206             return TRUE;
1207         }
1208
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 
1212         // other directly.
1213         //
1214         if ((pContext->GetMethodTable() == pMethod->GetMethodTable()) &&
1215             pContext->IsTightlyBoundToMethodTable() &&
1216             pMethod->IsTightlyBoundToMethodTable())
1217         {
1218             return TRUE;
1219         }
1220     }
1221     return FALSE;
1222 }
1223
1224 BOOL CEEPreloader::CanEmbedMethodHandle(CORINFO_METHOD_HANDLE methodHandle, 
1225                                         CORINFO_METHOD_HANDLE contextHandle)
1226 {
1227     STANDARD_VM_CONTRACT;
1228
1229     MethodDesc * pContext = GetMethod(contextHandle);
1230     MethodDesc * pMethod  = GetMethod(methodHandle);
1231
1232     if (CanEmbedMethodDescViaContext(pMethod, pContext))
1233         return TRUE;
1234
1235     return m_image->CanEagerBindToMethodDesc(pMethod);
1236 }
1237
1238 BOOL CEEPreloader::CanEmbedFieldHandle(CORINFO_FIELD_HANDLE    fieldHandle)
1239 {
1240     STANDARD_VM_CONTRACT;
1241
1242     return m_image->CanEagerBindToFieldDesc((FieldDesc *) fieldHandle);
1243
1244 }
1245
1246 void* CEECompileInfo::GetStubSize(void *pStubAddress, DWORD *pSizeToCopy)
1247 {
1248     CONTRACT(void*)
1249     {
1250         STANDARD_VM_CHECK;
1251         PRECONDITION(pStubAddress && pSizeToCopy);
1252     }
1253     CONTRACT_END;
1254
1255     Stub *stub = Stub::RecoverStubAndSize((TADDR)pStubAddress, pSizeToCopy);
1256     _ASSERTE(*pSizeToCopy > sizeof(Stub));
1257     RETURN stub;
1258 }
1259
1260 HRESULT CEECompileInfo::GetStubClone(void *pStub, BYTE *pBuffer, DWORD dwBufferSize)
1261 {
1262     STANDARD_VM_CONTRACT;
1263
1264     if (pStub == NULL)
1265     {
1266         return E_INVALIDARG;
1267     }
1268
1269     return (reinterpret_cast<Stub *>(pStub)->CloneStub(pBuffer, dwBufferSize));
1270 }
1271
1272 HRESULT CEECompileInfo::GetTypeDef(CORINFO_CLASS_HANDLE classHandle,
1273                                    mdTypeDef *token)
1274 {
1275     STANDARD_VM_CONTRACT;
1276
1277     CANNOTTHROWCOMPLUSEXCEPTION();
1278
1279     TypeHandle hClass(classHandle);
1280
1281     *token = hClass.GetCl();
1282
1283     return S_OK;
1284 }
1285
1286 HRESULT CEECompileInfo::GetMethodDef(CORINFO_METHOD_HANDLE methodHandle,
1287                                      mdMethodDef *token)
1288 {
1289     STANDARD_VM_CONTRACT;
1290
1291     CANNOTTHROWCOMPLUSEXCEPTION();
1292
1293     *token = ((MethodDesc*)methodHandle)->GetMemberDef();
1294
1295     return S_OK;
1296 }
1297
1298 /*********************************************************************/
1299 // Used to determine if a methodHandle can be embedded in an ngen image.
1300 // Depends on what things are persisted by CEEPreloader
1301
1302 BOOL CEEPreloader::CanEmbedFunctionEntryPoint(
1303     CORINFO_METHOD_HANDLE   methodHandle,
1304     CORINFO_METHOD_HANDLE   contextHandle, /* = NULL */
1305     CORINFO_ACCESS_FLAGS    accessFlags /*=CORINFO_ACCESS_ANY*/)
1306 {
1307     STANDARD_VM_CONTRACT;
1308
1309     MethodDesc * pMethod = GetMethod(methodHandle);
1310     MethodDesc * pContext = GetMethod(contextHandle);
1311
1312     // IsRemotingInterceptedViaVirtualDispatch is a rather special case.
1313     //
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.
1318     //
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.
1325     //
1326     if (((accessFlags & CORINFO_ACCESS_THIS) == 0) &&
1327         (pMethod->IsRemotingInterceptedViaVirtualDispatch()))
1328     {
1329         return FALSE;
1330     }
1331
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())
1337         return FALSE;
1338
1339     return TRUE;
1340 }
1341
1342 BOOL CEEPreloader::DoesMethodNeedRestoringBeforePrestubIsRun(
1343         CORINFO_METHOD_HANDLE   methodHandle)
1344 {
1345     STANDARD_VM_CONTRACT;
1346
1347     MethodDesc * ftn = GetMethod(methodHandle);
1348
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.
1353
1354     //@TODO: The reduction may be overkill, and we may consider refining the cases.
1355
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.
1368
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.
1371
1372     if (ftn->HasClassOrMethodInstantiation())
1373     {
1374         if (ftn->NeedsRestore(m_image))
1375             return TRUE;
1376     }
1377
1378     return FALSE;
1379 }
1380
1381 BOOL CEECompileInfo::IsNativeCallableMethod(CORINFO_METHOD_HANDLE handle)
1382 {
1383     WRAPPER_NO_CONTRACT;
1384
1385     MethodDesc * pMethod = GetMethod(handle);
1386     return pMethod->HasNativeCallableAttribute();
1387 }
1388
1389 BOOL CEEPreloader::CanSkipDependencyActivation(CORINFO_METHOD_HANDLE   context,
1390                                                CORINFO_MODULE_HANDLE   moduleFrom,
1391                                                CORINFO_MODULE_HANDLE   moduleTo)
1392 {
1393     STANDARD_VM_CONTRACT;
1394
1395     // Can't skip any fixups for speculative generic instantiations
1396     if (Module::GetPreferredZapModuleForMethodDesc(GetMethod(context)) != m_image->GetModule())
1397         return FALSE;
1398
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);
1402 }
1403
1404 CORINFO_MODULE_HANDLE CEEPreloader::GetPreferredZapModuleForClassHandle(
1405         CORINFO_CLASS_HANDLE classHnd)
1406 {
1407     STANDARD_VM_CONTRACT;
1408
1409     return CORINFO_MODULE_HANDLE(Module::GetPreferredZapModuleForTypeHandle(TypeHandle(classHnd)));
1410 }
1411
1412 // This method is called directly from zapper
1413 extern BOOL CanDeduplicateCode(CORINFO_METHOD_HANDLE method, CORINFO_METHOD_HANDLE duplicateMethod);
1414
1415 BOOL CanDeduplicateCode(CORINFO_METHOD_HANDLE method, CORINFO_METHOD_HANDLE duplicateMethod)
1416 {
1417     CONTRACTL
1418     {
1419         NOTHROW;
1420         GC_NOTRIGGER;
1421     }
1422     CONTRACTL_END;
1423
1424     ENABLE_FORBID_GC_LOADER_USE_IN_THIS_SCOPE();
1425
1426     // For now, the deduplication is supported for IL stubs only
1427     DynamicMethodDesc * pMethod = GetMethod(method)->AsDynamicMethodDesc();
1428     DynamicMethodDesc * pDuplicateMethod = GetMethod(duplicateMethod)->AsDynamicMethodDesc();
1429
1430     //
1431     // Make sure that the return types match (for code:Thread::HijackThread)
1432     //
1433
1434 #ifdef _TARGET_X86_
1435     MetaSig msig1(pMethod);
1436     MetaSig msig2(pDuplicateMethod);
1437     if (!msig1.HasFPReturn() != !msig2.HasFPReturn())
1438         return FALSE;
1439 #endif // _TARGET_X86_
1440
1441     MetaSig::RETURNTYPE returnType = pMethod->ReturnsObject();
1442     MetaSig::RETURNTYPE returnTypeDuplicate = pDuplicateMethod->ReturnsObject();
1443
1444     if (returnType != returnTypeDuplicate)
1445         return FALSE;
1446
1447     //
1448     // Do not enable deduplication of structs returned in registers
1449     //
1450
1451     if (returnType == MetaSig::RETVALUETYPE)
1452         return FALSE;
1453
1454     //
1455     // Make sure that the IL stub flags match
1456     //
1457
1458     if (pMethod->GetExtendedFlags() != pDuplicateMethod->GetExtendedFlags())
1459         return FALSE;
1460
1461     return TRUE;
1462 }
1463
1464 void CEEPreloader::NoteDeduplicatedCode(CORINFO_METHOD_HANDLE method, CORINFO_METHOD_HANDLE duplicateMethod)
1465 {
1466     STANDARD_VM_CONTRACT;
1467
1468 #ifndef FEATURE_FULL_NGEN // Deduplication
1469     DuplicateMethodEntry e;
1470     e.pMD = GetMethod(method);
1471     e.pDuplicateMD = GetMethod(duplicateMethod);
1472     m_duplicateMethodsHash.Add(e);
1473 #endif
1474 }
1475
1476 HRESULT CEECompileInfo::GetFieldDef(CORINFO_FIELD_HANDLE fieldHandle,
1477                                     mdFieldDef *token)
1478 {
1479     STANDARD_VM_CONTRACT;
1480
1481     CANNOTTHROWCOMPLUSEXCEPTION();
1482
1483     *token = ((FieldDesc*)fieldHandle)->GetMemberDef();
1484
1485     return S_OK;
1486 }
1487
1488 void CEECompileInfo::EncodeModuleAsIndexes(CORINFO_MODULE_HANDLE  fromHandle,
1489                                            CORINFO_MODULE_HANDLE  handle,
1490                                            DWORD*                 pAssemblyIndex,
1491                                            DWORD*                 pModuleIndex,
1492                                            IMetaDataAssemblyEmit* pAssemblyEmit)
1493 {
1494     STANDARD_VM_CONTRACT;
1495
1496     COOPERATIVE_TRANSITION_BEGIN();
1497
1498     Module *fromModule = GetModule(fromHandle);
1499     Assembly *fromAssembly = fromModule->GetAssembly();
1500
1501     Module *module = GetModule(handle);
1502     Assembly *assembly = module->GetAssembly();
1503
1504     if (assembly == fromAssembly)
1505         *pAssemblyIndex = 0;
1506     else
1507     {
1508         UPTR    result;
1509         mdToken token;
1510
1511         CompilationDomain *pDomain = GetAppDomain()->ToCompilationDomain();
1512     
1513         RefCache *pRefCache = pDomain->GetRefCache(fromModule);
1514         if (!pRefCache)
1515             ThrowOutOfMemory();
1516
1517         
1518         if (!assembly->GetManifestFile()->HasBindableIdentity())
1519         {
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());
1528
1529             AssemblySpec* pRefSpec = pDomain->FindAssemblyRefSpecForDefSpec(&defSpec);
1530             _ASSERTE(pRefSpec != nullptr);
1531
1532             IfFailThrow(pRefSpec->EmitToken(pAssemblyEmit, &token, TRUE, TRUE));
1533             token += fromModule->GetAssemblyRefMax();
1534         }
1535         else
1536         {
1537             result = pRefCache->m_sAssemblyRefMap.LookupValue((UPTR)assembly, NULL);
1538
1539             if (result == (UPTR)INVALIDENTRY)
1540                 token = fromModule->FindAssemblyRef(assembly);
1541             else
1542                 token = (mdAssemblyRef) result;
1543
1544             if (IsNilToken(token))
1545             {
1546                 token = fromAssembly->AddAssemblyRef(assembly, pAssemblyEmit);
1547                 token += fromModule->GetAssemblyRefMax();
1548             }
1549         }
1550
1551         *pAssemblyIndex = RidFromToken(token);
1552
1553         pRefCache->m_sAssemblyRefMap.InsertValue((UPTR) assembly, (UPTR)token);
1554     }
1555
1556     if (module == assembly->GetManifestModule())
1557         *pModuleIndex = 0;
1558     else
1559     {
1560         _ASSERTE(module->GetModuleRef() != mdFileNil);
1561         *pModuleIndex = RidFromToken(module->GetModuleRef());
1562     }
1563
1564     COOPERATIVE_TRANSITION_END();
1565 }
1566
1567 void CEECompileInfo::EncodeClass(
1568                          CORINFO_MODULE_HANDLE referencingModule,
1569                          CORINFO_CLASS_HANDLE  classHandle,
1570                          SigBuilder *          pSigBuilder,
1571                          LPVOID                pEncodeModuleContext,
1572                          ENCODEMODULE_CALLBACK pfnEncodeModule)
1573 {
1574     STANDARD_VM_CONTRACT;
1575
1576     TypeHandle th(classHandle);
1577
1578     ZapSig zapSig((Module *)referencingModule, pEncodeModuleContext, ZapSig::NormalTokens,
1579                   (EncodeModuleCallback) pfnEncodeModule, NULL);
1580
1581     COOPERATIVE_TRANSITION_BEGIN();
1582
1583     BOOL fSuccess;
1584     fSuccess = zapSig.GetSignatureForTypeHandle(th, pSigBuilder);
1585     _ASSERTE(fSuccess);
1586
1587     COOPERATIVE_TRANSITION_END();
1588 }
1589
1590 CORINFO_MODULE_HANDLE CEECompileInfo::GetLoaderModuleForMscorlib()
1591 {
1592     STANDARD_VM_CONTRACT;
1593
1594     return CORINFO_MODULE_HANDLE(SystemDomain::SystemModule());
1595 }
1596
1597 CORINFO_MODULE_HANDLE CEECompileInfo::GetLoaderModuleForEmbeddableType(CORINFO_CLASS_HANDLE clsHnd)
1598 {
1599     STANDARD_VM_CONTRACT;
1600
1601     TypeHandle t = TypeHandle(clsHnd);
1602     return CORINFO_MODULE_HANDLE(t.GetLoaderModule());
1603 }
1604
1605 CORINFO_MODULE_HANDLE CEECompileInfo::GetLoaderModuleForEmbeddableMethod(CORINFO_METHOD_HANDLE methHnd)
1606 {
1607     STANDARD_VM_CONTRACT;
1608
1609     MethodDesc *pMD = GetMethod(methHnd);
1610     return CORINFO_MODULE_HANDLE(pMD->GetLoaderModule());
1611 }
1612
1613 CORINFO_MODULE_HANDLE CEECompileInfo::GetLoaderModuleForEmbeddableField(CORINFO_FIELD_HANDLE fieldHnd)
1614 {
1615     STANDARD_VM_CONTRACT;
1616
1617     FieldDesc *pFD = (FieldDesc *) fieldHnd;
1618     return CORINFO_MODULE_HANDLE(pFD->GetLoaderModule());
1619 }
1620
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)
1630 {
1631     STANDARD_VM_CONTRACT;
1632
1633     COOPERATIVE_TRANSITION_BEGIN();
1634     MethodDesc *pMethod = GetMethod(handle);
1635
1636     BOOL fSuccess;
1637     fSuccess = ZapSig::EncodeMethod(pMethod, 
1638                               (Module *) referencingModule,
1639                               pSigBuilder,
1640                               pEncodeModuleContext, 
1641                               pfnEncodeModule, NULL,
1642                               pResolvedToken, pConstrainedResolvedToken,
1643                               fEncodeUsingResolvedTokenSpecStreams);
1644     _ASSERTE(fSuccess);
1645
1646     COOPERATIVE_TRANSITION_END();
1647 }
1648
1649 mdToken CEECompileInfo::TryEncodeMethodAsToken(
1650                 CORINFO_METHOD_HANDLE handle,
1651                 CORINFO_RESOLVED_TOKEN * pResolvedToken,
1652                 CORINFO_MODULE_HANDLE * referencingModule)
1653 {
1654     STANDARD_VM_CONTRACT;
1655
1656     MethodDesc * pMethod = GetMethod(handle);
1657
1658 #ifdef FEATURE_READYTORUN_COMPILER
1659     if (IsReadyToRunCompilation())
1660     {
1661         _ASSERTE(pResolvedToken != NULL);
1662
1663         Module * pReferencingModule = (Module *)pResolvedToken->tokenScope;
1664
1665         if (!pReferencingModule->IsInCurrentVersionBubble())
1666             return mdTokenNil;
1667
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)
1672             return mdTokenNil;
1673             
1674         unsigned methodToken = pResolvedToken->token;
1675
1676         switch (TypeFromToken(methodToken))
1677         {
1678         case mdtMethodDef:
1679             if (pReferencingModule->LookupMethodDef(methodToken) != pMethod)
1680                 return mdTokenNil;
1681             break;
1682
1683         case mdtMemberRef:
1684             if (pReferencingModule->LookupMemberRefAsMethod(methodToken) != pMethod)
1685                 return mdTokenNil;
1686             break;
1687
1688         default:
1689             return mdTokenNil;
1690         }
1691
1692         *referencingModule = CORINFO_MODULE_HANDLE(pReferencingModule);
1693         return methodToken;
1694     }
1695 #endif // FEATURE_READYTORUN_COMPILER
1696
1697     Module *pModule = pMethod->GetModule();
1698     if (!pModule->IsInCurrentVersionBubble())
1699     {
1700         Module * pTargetModule = GetAppDomain()->ToCompilationDomain()->GetTargetModule();
1701         *referencingModule = CORINFO_MODULE_HANDLE(pTargetModule);
1702         return pTargetModule->LookupMemberRefByMethodDesc(pMethod);
1703     }
1704     else
1705     {
1706         mdToken defToken = pMethod->GetMemberDef();
1707         if (pModule->LookupMethodDef(defToken) == pMethod)
1708         {
1709             *referencingModule = CORINFO_MODULE_HANDLE(pModule);
1710             return defToken;
1711         }
1712     }
1713
1714     return mdTokenNil;
1715 }
1716
1717 DWORD CEECompileInfo::TryEncodeMethodSlot(CORINFO_METHOD_HANDLE handle)
1718 {
1719     STANDARD_VM_CONTRACT;
1720
1721     MethodDesc * pMethod = GetMethod(handle);
1722
1723 #ifdef FEATURE_READYTORUN_COMPILER
1724     if (IsReadyToRunCompilation())
1725     {
1726         // We can only encode real interface methods as slots
1727         if (!pMethod->IsInterface() || pMethod->IsStatic())
1728             return (DWORD)-1;
1729
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())
1734             return (DWORD)-1;
1735     }
1736 #endif
1737
1738     return pMethod->GetSlot();
1739 }
1740
1741 void EncodeTypeInDictionarySignature(
1742             Module * pInfoModule,
1743             SigPointer ptr, 
1744             SigBuilder * pSigBuilder,
1745             LPVOID encodeContext,
1746             ENCODEMODULE_CALLBACK pfnEncodeModule)
1747 {
1748     STANDARD_VM_CONTRACT;
1749
1750     CorElementType typ = ELEMENT_TYPE_END;
1751     IfFailThrow(ptr.GetElemType(&typ));
1752
1753     if (typ == ELEMENT_TYPE_INTERNAL)
1754     {
1755         TypeHandle th;
1756
1757         IfFailThrow(ptr.GetPointer((void**)&th));
1758
1759         ZapSig zapSig(pInfoModule, encodeContext, ZapSig::NormalTokens,
1760                       (EncodeModuleCallback) pfnEncodeModule, NULL);
1761
1762         //
1763         // Write class
1764         //
1765         BOOL fSuccess;
1766         fSuccess = zapSig.GetSignatureForTypeHandle(th, pSigBuilder);
1767         _ASSERTE(fSuccess);
1768
1769         return;
1770     }
1771     else
1772     if (typ == ELEMENT_TYPE_GENERICINST)
1773     {
1774         //
1775         // SigParser expects ELEMENT_TYPE_MODULE_ZAPSIG to be before ELEMENT_TYPE_GENERICINST
1776         //
1777         SigPointer peek(ptr);
1778         ULONG instType = 0;
1779         IfFailThrow(peek.GetData(&instType));
1780         _ASSERTE(instType == ELEMENT_TYPE_INTERNAL);
1781
1782         TypeHandle th;
1783         IfFailThrow(peek.GetPointer((void **)&th));
1784
1785         Module * pTypeHandleModule = th.GetModule();
1786
1787         if (!pTypeHandleModule->IsInCurrentVersionBubble())
1788         {
1789             pTypeHandleModule = GetAppDomain()->ToCompilationDomain()->GetTargetModule();
1790         }
1791
1792         if (pTypeHandleModule != pInfoModule)
1793         {
1794             DWORD index = pfnEncodeModule(encodeContext, (CORINFO_MODULE_HANDLE)pTypeHandleModule);
1795             _ASSERTE(index != ENCODE_MODULE_FAILED);
1796
1797             pSigBuilder->AppendElementType((CorElementType) ELEMENT_TYPE_MODULE_ZAPSIG);
1798             pSigBuilder->AppendData(index);
1799         }
1800
1801         pSigBuilder->AppendElementType(ELEMENT_TYPE_GENERICINST);
1802
1803         EncodeTypeInDictionarySignature(pTypeHandleModule, ptr, pSigBuilder, encodeContext, pfnEncodeModule);
1804         IfFailThrow(ptr.SkipExactlyOne());
1805
1806         ULONG argCnt = 0; // Get number of parameters
1807         IfFailThrow(ptr.GetData(&argCnt));
1808         pSigBuilder->AppendData(argCnt);
1809
1810         while (argCnt--)
1811         {
1812             EncodeTypeInDictionarySignature(pInfoModule, ptr, pSigBuilder, encodeContext, pfnEncodeModule);
1813             IfFailThrow(ptr.SkipExactlyOne());
1814         }
1815
1816         return;
1817     }
1818     else if((CorElementTypeZapSig)typ == ELEMENT_TYPE_NATIVE_ARRAY_TEMPLATE_ZAPSIG)
1819     {
1820         pSigBuilder->AppendElementType((CorElementType)ELEMENT_TYPE_NATIVE_ARRAY_TEMPLATE_ZAPSIG);
1821
1822         IfFailThrow(ptr.GetElemType(&typ));
1823
1824         _ASSERTE(typ == ELEMENT_TYPE_SZARRAY || typ == ELEMENT_TYPE_ARRAY);
1825     }
1826
1827     pSigBuilder->AppendElementType(typ);
1828
1829     if (!CorIsPrimitiveType(typ))
1830     {
1831         switch (typ)
1832         {
1833             case ELEMENT_TYPE_VAR:
1834             case ELEMENT_TYPE_MVAR:
1835                 {
1836                     ULONG varNum;
1837                     // Skip variable number
1838                     IfFailThrow(ptr.GetData(&varNum));
1839                     pSigBuilder->AppendData(varNum);
1840                 }
1841                 break;
1842             case ELEMENT_TYPE_OBJECT:
1843             case ELEMENT_TYPE_STRING:
1844             case ELEMENT_TYPE_TYPEDBYREF:
1845                 break;
1846
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());
1853                 break;
1854
1855             case ELEMENT_TYPE_ARRAY:
1856                 {
1857                     EncodeTypeInDictionarySignature(pInfoModule, ptr, pSigBuilder, encodeContext, pfnEncodeModule);
1858                     IfFailThrow(ptr.SkipExactlyOne());
1859
1860                     ULONG rank = 0; // Get rank
1861                     IfFailThrow(ptr.GetData(&rank));
1862                     pSigBuilder->AppendData(rank);
1863
1864                     if (rank)
1865                     {
1866                         ULONG nsizes = 0;
1867                         IfFailThrow(ptr.GetData(&nsizes));
1868                         pSigBuilder->AppendData(nsizes);
1869
1870                         while (nsizes--)
1871                         {
1872                             ULONG data = 0;
1873                             IfFailThrow(ptr.GetData(&data));
1874                             pSigBuilder->AppendData(data);
1875                         }
1876
1877                         ULONG nlbounds = 0;
1878                         IfFailThrow(ptr.GetData(&nlbounds));
1879                         pSigBuilder->AppendData(nlbounds);
1880
1881                         while (nlbounds--)
1882                         {
1883                             ULONG data = 0;
1884                             IfFailThrow(ptr.GetData(&data));
1885                             pSigBuilder->AppendData(data);
1886                         }
1887                     }
1888                 }
1889                 break;
1890
1891             default:
1892                 _ASSERTE(!"Unexpected element in signature");
1893         }
1894     }
1895 }
1896
1897 void CEECompileInfo::EncodeGenericSignature(
1898             LPVOID signature,
1899             BOOL fMethod,
1900             SigBuilder * pSigBuilder,
1901             LPVOID encodeContext,
1902             ENCODEMODULE_CALLBACK pfnEncodeModule)
1903 {
1904     STANDARD_VM_CONTRACT;
1905
1906     Module * pInfoModule = MscorlibBinder::GetModule();
1907
1908     SigPointer ptr((PCCOR_SIGNATURE)signature);
1909
1910     ULONG entryKind; // DictionaryEntryKind
1911     IfFailThrow(ptr.GetData(&entryKind));
1912     pSigBuilder->AppendData(entryKind);
1913
1914     if (!fMethod)
1915     {
1916         ULONG dictionaryIndex = 0;
1917         IfFailThrow(ptr.GetData(&dictionaryIndex));
1918
1919         pSigBuilder->AppendData(dictionaryIndex);
1920     }
1921
1922     switch (entryKind)
1923     {
1924     case DeclaringTypeHandleSlot:
1925         EncodeTypeInDictionarySignature(pInfoModule, ptr, pSigBuilder, encodeContext, pfnEncodeModule);
1926         IfFailThrow(ptr.SkipExactlyOne());
1927         // fall through
1928
1929     case TypeHandleSlot:
1930         EncodeTypeInDictionarySignature(pInfoModule, ptr, pSigBuilder, encodeContext, pfnEncodeModule);
1931         IfFailThrow(ptr.SkipExactlyOne());
1932         break;
1933
1934     case ConstrainedMethodEntrySlot:
1935         EncodeTypeInDictionarySignature(pInfoModule, ptr, pSigBuilder, encodeContext, pfnEncodeModule);
1936         IfFailThrow(ptr.SkipExactlyOne());
1937         // fall through
1938
1939     case MethodDescSlot:
1940     case MethodEntrySlot:
1941     case DispatchStubAddrSlot:
1942         {
1943             EncodeTypeInDictionarySignature(pInfoModule, ptr, pSigBuilder, encodeContext, pfnEncodeModule);
1944             IfFailThrow(ptr.SkipExactlyOne());
1945
1946             ULONG methodFlags;
1947             IfFailThrow(ptr.GetData(&methodFlags));
1948             pSigBuilder->AppendData(methodFlags);
1949
1950             if ((methodFlags & ENCODE_METHOD_SIG_SlotInsteadOfToken) == 0)
1951             {
1952                 EncodeTypeInDictionarySignature(pInfoModule, ptr, pSigBuilder, encodeContext, pfnEncodeModule);
1953                 IfFailThrow(ptr.SkipExactlyOne());
1954             }
1955             
1956             ULONG tokenOrSlot;
1957             IfFailThrow(ptr.GetData(&tokenOrSlot));
1958             pSigBuilder->AppendData(tokenOrSlot);
1959
1960             if (methodFlags & ENCODE_METHOD_SIG_MethodInstantiation)
1961             {
1962                 DWORD nGenericMethodArgs;
1963                 IfFailThrow(ptr.GetData(&nGenericMethodArgs));
1964                 pSigBuilder->AppendData(nGenericMethodArgs);
1965
1966                 for (DWORD i = 0; i < nGenericMethodArgs; i++)
1967                 {
1968                     EncodeTypeInDictionarySignature(pInfoModule, ptr, pSigBuilder, encodeContext, pfnEncodeModule);
1969                     IfFailThrow(ptr.SkipExactlyOne());
1970                 }
1971             }
1972         }
1973         break;
1974
1975     case FieldDescSlot:
1976         {
1977             EncodeTypeInDictionarySignature(pInfoModule, ptr, pSigBuilder, encodeContext, pfnEncodeModule);
1978             IfFailThrow(ptr.SkipExactlyOne());
1979
1980             DWORD fieldIndex;
1981             IfFailThrow(ptr.GetData(&fieldIndex));
1982             pSigBuilder->AppendData(fieldIndex);
1983         }
1984         break;
1985
1986     default:
1987         _ASSERTE(false);
1988     }
1989
1990     ULONG dictionarySlot;
1991     IfFailThrow(ptr.GetData(&dictionarySlot));
1992     pSigBuilder->AppendData(dictionarySlot);
1993 }
1994
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)
2003 {
2004     STANDARD_VM_CONTRACT;
2005
2006     COOPERATIVE_TRANSITION_BEGIN();
2007
2008     ZapSig::EncodeField(GetField(handle), 
2009                         (Module *) referencingModule,
2010                         pSigBuilder,
2011                         encodeContext, 
2012                         pfnEncodeModule,
2013                         pResolvedToken,
2014                         fEncodeUsingResolvedTokenSpecStreams);
2015
2016     COOPERATIVE_TRANSITION_END();
2017 }
2018
2019 BOOL CEECompileInfo::IsEmptyString(mdString token,
2020                                    CORINFO_MODULE_HANDLE module)
2021 {
2022     STANDARD_VM_CONTRACT;
2023
2024     BOOL fRet = FALSE;
2025
2026     COOPERATIVE_TRANSITION_BEGIN();
2027
2028     EEStringData strData;
2029     ((Module *)module)->InitializeStringData(token, &strData, NULL);
2030     fRet = (strData.GetCharCount() == 0);
2031
2032     COOPERATIVE_TRANSITION_END();
2033
2034     return fRet;
2035 }
2036
2037 #ifdef FEATURE_READYTORUN_COMPILER
2038 CORCOMPILE_FIXUP_BLOB_KIND CEECompileInfo::GetFieldBaseOffset(
2039         CORINFO_CLASS_HANDLE classHnd,
2040         DWORD * pBaseOffset)
2041 {
2042     STANDARD_VM_CONTRACT;
2043
2044     MethodTable * pMT = (MethodTable *)classHnd;
2045     Module * pModule = pMT->GetModule();
2046
2047     if (!pMT->IsLayoutFixedInCurrentVersionBubble())
2048     {
2049         return pMT->IsValueType() ? ENCODE_CHECK_FIELD_OFFSET : ENCODE_FIELD_OFFSET;
2050     }
2051
2052     if (pMT->IsValueType())
2053     {
2054         return ENCODE_NONE;
2055     }
2056
2057     if (pMT->GetParentMethodTable()->IsInheritanceChainLayoutFixedInCurrentVersionBubble())
2058     {
2059         return ENCODE_NONE;
2060     }
2061
2062     if (pMT->HasLayout())
2063     {
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;
2067     }
2068
2069     *pBaseOffset = ReadyToRunInfo::GetFieldBaseOffset(pMT);
2070     return ENCODE_FIELD_BASE_OFFSET;
2071 }
2072
2073 BOOL CEECompileInfo::NeedsTypeLayoutCheck(CORINFO_CLASS_HANDLE classHnd)
2074 {
2075     STANDARD_VM_CONTRACT;
2076
2077     TypeHandle th(classHnd);
2078
2079     if (th.IsTypeDesc())
2080         return FALSE;
2081
2082     MethodTable * pMT = th.AsMethodTable();
2083
2084     if (!pMT->IsValueType())
2085         return FALSE;
2086
2087     // Skip this check for equivalent types. Equivalent types are used for interop that ensures
2088     // matching layout.
2089     if (pMT->GetClass()->IsEquivalentType())
2090         return FALSE;
2091
2092     return !pMT->IsLayoutFixedInCurrentVersionBubble();
2093 }
2094
2095 extern void ComputeGCRefMap(MethodTable * pMT, BYTE * pGCRefMap, size_t cbGCRefMap);
2096
2097 void CEECompileInfo::EncodeTypeLayout(CORINFO_CLASS_HANDLE classHandle, SigBuilder * pSigBuilder)
2098 {
2099     STANDARD_VM_CONTRACT;
2100
2101     MethodTable * pMT = TypeHandle(classHandle).AsMethodTable();
2102     _ASSERTE(pMT->IsValueType());
2103
2104     DWORD dwSize = pMT->GetNumInstanceFieldBytes();
2105     DWORD dwAlignment = CEEInfo::getClassAlignmentRequirementStatic(pMT);
2106
2107     DWORD dwFlags = 0;
2108
2109 #ifdef FEATURE_HFA
2110     if (pMT->IsHFA())
2111         dwFlags |= READYTORUN_LAYOUT_HFA;
2112 #endif
2113
2114     // Check everything 
2115     dwFlags |= READYTORUN_LAYOUT_Alignment;
2116     if (dwAlignment == sizeof(void *))
2117         dwFlags |= READYTORUN_LAYOUT_Alignment_Native;
2118
2119     dwFlags |= READYTORUN_LAYOUT_GCLayout;
2120     if (!pMT->ContainsPointers())
2121         dwFlags |= READYTORUN_LAYOUT_GCLayout_Empty;
2122
2123     pSigBuilder->AppendData(dwFlags);
2124
2125     // Size is checked unconditionally
2126     pSigBuilder->AppendData(dwSize);
2127
2128 #ifdef FEATURE_HFA
2129     if (dwFlags & READYTORUN_LAYOUT_HFA)
2130     {
2131         pSigBuilder->AppendData(pMT->GetHFAType());
2132     }
2133 #endif
2134
2135     if ((dwFlags & READYTORUN_LAYOUT_Alignment) && !(dwFlags & READYTORUN_LAYOUT_Alignment_Native))
2136     {
2137         pSigBuilder->AppendData(dwAlignment);
2138     }
2139
2140     if ((dwFlags & READYTORUN_LAYOUT_GCLayout) && !(dwFlags & READYTORUN_LAYOUT_GCLayout_Empty))
2141     {
2142         size_t cbGCRefMap = (dwSize / sizeof(TADDR) + 7) / 8;
2143         _ASSERTE(cbGCRefMap > 0);
2144
2145         BYTE * pGCRefMap = (BYTE *)_alloca(cbGCRefMap);
2146
2147         ComputeGCRefMap(pMT, pGCRefMap, cbGCRefMap);
2148
2149         for (size_t i = 0; i < cbGCRefMap; i++)
2150             pSigBuilder->AppendByte(pGCRefMap[i]);
2151     }
2152 }
2153
2154 BOOL CEECompileInfo::AreAllClassesFullyLoaded(CORINFO_MODULE_HANDLE moduleHandle)
2155 {
2156     STANDARD_VM_CONTRACT;
2157
2158     return ((Module *)moduleHandle)->AreAllClassesFullyLoaded();
2159 }
2160
2161 int CEECompileInfo::GetVersionResilientTypeHashCode(CORINFO_MODULE_HANDLE moduleHandle, mdToken token)
2162 {
2163     STANDARD_VM_CONTRACT;
2164
2165     int dwHashCode;
2166     if (!::GetVersionResilientTypeHashCode(((Module *)moduleHandle)->GetMDImport(), token, &dwHashCode))
2167         ThrowHR(COR_E_BADIMAGEFORMAT);
2168
2169     return dwHashCode;
2170 }
2171
2172 int CEECompileInfo::GetVersionResilientMethodHashCode(CORINFO_METHOD_HANDLE methodHandle)
2173 {
2174     STANDARD_VM_CONTRACT;
2175
2176     return ::GetVersionResilientMethodHashCode(GetMethod(methodHandle));
2177 }
2178
2179 #endif // FEATURE_READYTORUN_COMPILER
2180
2181 BOOL CEECompileInfo::HasCustomAttribute(CORINFO_METHOD_HANDLE method, LPCSTR customAttributeName)
2182 {
2183     STANDARD_VM_CONTRACT;
2184
2185     MethodDesc * pMD = GetMethod(method);
2186     return S_OK == pMD->GetMDImport()->GetCustomAttributeByName(pMD->GetMemberDef(), customAttributeName, NULL, NULL);
2187 }
2188
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
2199
2200 #define OMF_StandardText  (OMFConst_FSel|OMFConst_F32Bit|OMFConst_Exec|OMFConst_Read) // 0x10D
2201 #define OMF_SentinelType  (OMFConst_FAbs|OMFConst_F32Bit) // 0x208
2202
2203
2204 // ----------------------------------------------------------------------------
2205 // NGEN PDB SUPPORT
2206 // 
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.
2210 // 
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 // ----------------------------------------------------------------------------
2215
2216 #if defined(NO_NGENPDB) && !defined(FEATURE_PERFMAP)
2217 BOOL CEECompileInfo::GetIsGeneratingNgenPDB() 
2218 {
2219     return FALSE; 
2220 }
2221
2222 void CEECompileInfo::SetIsGeneratingNgenPDB(BOOL fGeneratingNgenPDB) 
2223 {
2224 }
2225
2226 BOOL IsNgenPDBCompilationProcess()
2227 {
2228     return FALSE;
2229 }
2230 #else
2231 BOOL CEECompileInfo::GetIsGeneratingNgenPDB() 
2232 {
2233     LIMITED_METHOD_DAC_CONTRACT;
2234     return m_fGeneratingNgenPDB; 
2235 }
2236
2237 void CEECompileInfo::SetIsGeneratingNgenPDB(BOOL fGeneratingNgenPDB) 
2238 {
2239     LIMITED_METHOD_DAC_CONTRACT;
2240     m_fGeneratingNgenPDB = fGeneratingNgenPDB; 
2241 }
2242
2243 BOOL IsNgenPDBCompilationProcess()
2244 {
2245     LIMITED_METHOD_DAC_CONTRACT;
2246     return IsCompilationProcess() && g_pCEECompileInfo->GetIsGeneratingNgenPDB();
2247 }
2248
2249 #endif // NO_NGENPDB && !FEATURE_PERFMAP
2250
2251 #ifndef NO_NGENPDB
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);
2254
2255 // Allocator to specify when requesting boundaries information for PDB
2256 BYTE* SimpleNew(void *, size_t cBytes)
2257 {
2258     CONTRACTL
2259     {
2260         THROWS;
2261         GC_NOTRIGGER;
2262         MODE_ANY;
2263     }
2264     CONTRACTL_END;
2265
2266     BYTE * p = new BYTE[cBytes];
2267     return p;
2268 }
2269
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;
2273
2274
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.
2278 // 
2279 struct DocNameOffsets
2280 {
2281     ULONG32 m_dwStrTableOffset;
2282     ULONG32 m_dwChksumTableOffset;
2283     DocNameOffsets(ULONG32 dwStrTableOffset, ULONG32 dwChksumTableOffset)
2284         : m_dwStrTableOffset(dwStrTableOffset), m_dwChksumTableOffset(dwChksumTableOffset)
2285     {
2286         LIMITED_METHOD_CONTRACT;
2287     }
2288
2289     DocNameOffsets()
2290         : m_dwStrTableOffset((ULONG32) -1), m_dwChksumTableOffset((ULONG32) -1)
2291     {
2292         LIMITED_METHOD_CONTRACT;
2293     }
2294 };
2295
2296
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
2301 //         names
2302 //     * Hashing is done by hashing the source file names
2303 //     
2304 struct DocNameToOffsetMapTraits : public NoRemoveSHashTraits < MapSHashTraits<LPCSTR, DocNameOffsets> >
2305 {
2306 public:
2307     static BOOL Equals(key_t k1, key_t k2)
2308     {
2309         LIMITED_METHOD_CONTRACT;
2310
2311         if (k1 == NULL && k2 == NULL)
2312             return TRUE;
2313         if (k1 == NULL || k2 == NULL)
2314             return FALSE;
2315         return _stricmp(k1, k2) == 0;
2316     }
2317
2318     static count_t Hash(key_t k)
2319     {
2320         LIMITED_METHOD_CONTRACT;
2321
2322         if (k == NULL)
2323             return 0;
2324         else
2325             return HashiStringA(k);
2326     }
2327
2328     typedef LPCSTR KEY;
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; }
2334 };
2335
2336
2337 // ----------------------------------------------------------------------------
2338 // Hash table that maps the UTF-8 string of a source file name to its corresponding
2339 // DocNameToOffsetMapTraits
2340 // 
2341 class DocNameToOffsetMap : public SHash<DocNameToOffsetMapTraits>
2342 {
2343     typedef SHash<DocNameToOffsetMapTraits> PARENT;
2344     typedef LPCSTR KEY;
2345     typedef DocNameOffsets VALUE;
2346     
2347 public:
2348     void Add(KEY key, VALUE value)
2349     {
2350         CONTRACTL
2351         {
2352             THROWS;
2353             GC_NOTRIGGER;
2354             PRECONDITION(key != (KEY)0);
2355         }
2356         CONTRACTL_END;
2357
2358         PARENT::Add(KeyValuePair<KEY,VALUE>(key, value));
2359     }
2360
2361     void AddOrReplace(KEY key, VALUE value)
2362     {
2363         CONTRACTL
2364         {
2365             THROWS;
2366             GC_NOTRIGGER;
2367             PRECONDITION(key != (KEY)0);
2368         }
2369         CONTRACTL_END;
2370
2371         PARENT::AddOrReplace(KeyValuePair<KEY,VALUE>(key, value));
2372     }
2373
2374     BOOL Lookup(KEY key, VALUE* pValue)
2375     {
2376         CONTRACTL
2377         {
2378             NOTHROW;
2379             GC_NOTRIGGER;
2380             PRECONDITION(key != (KEY)0);
2381         }
2382         CONTRACTL_END;
2383
2384         const KeyValuePair<KEY,VALUE> *pRet = PARENT::LookupPtr(key);
2385         if (pRet == NULL)
2386             return FALSE;
2387
2388         *pValue = pRet->Value();
2389         return TRUE;
2390     }
2391 };
2392
2393 // ----------------------------------------------------------------------------
2394 // Simple class to sort ICorDebugInfo::OffsetMapping arrays by IL offset
2395 // 
2396 class QuickSortILNativeMapByIL : public CQuickSort<ICorDebugInfo::OffsetMapping>
2397 {
2398   public:
2399     QuickSortILNativeMapByIL(
2400         ICorDebugInfo::OffsetMapping * rgMap,
2401         int cEntries)
2402       : CQuickSort<ICorDebugInfo::OffsetMapping>(rgMap, cEntries)
2403     {
2404         LIMITED_METHOD_CONTRACT;
2405     }
2406
2407     int Compare(ICorDebugInfo::OffsetMapping * pFirst,
2408                 ICorDebugInfo::OffsetMapping * pSecond)
2409     {
2410         LIMITED_METHOD_CONTRACT;
2411
2412         if (pFirst->ilOffset < pSecond->ilOffset)
2413             return -1;
2414         else if (pFirst->ilOffset == pSecond->ilOffset)
2415             return 0;
2416         else
2417             return 1;
2418     }
2419 };
2420
2421 // ----------------------------------------------------------------------------
2422 // Simple class to sort IL to Native mapping arrays by Native offset
2423 // 
2424 class QuickSortILNativeMapByNativeOffset : public CQuickSort<ICorDebugInfo::OffsetMapping>
2425 {
2426 public:
2427     QuickSortILNativeMapByNativeOffset(
2428         ICorDebugInfo::OffsetMapping * rgMap,
2429         int cEntries)
2430         : CQuickSort<ICorDebugInfo::OffsetMapping>(rgMap, cEntries)
2431     {
2432         LIMITED_METHOD_CONTRACT;
2433     }
2434
2435     int Compare(ICorDebugInfo::OffsetMapping * pFirst,
2436         ICorDebugInfo::OffsetMapping * pSecond)
2437     {
2438         LIMITED_METHOD_CONTRACT;
2439
2440         if (pFirst->nativeOffset < pSecond->nativeOffset)
2441             return -1;
2442         else if (pFirst->nativeOffset == pSecond->nativeOffset)
2443             return 0;
2444         else
2445             return 1;
2446     }
2447 };
2448
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.
2452 // 
2453 struct MapIndexPair
2454 {
2455 public:
2456     // Index into ICorDebugInfo::OffsetMapping
2457     ULONG32 m_iIlNativeMap;
2458     
2459     // Corresponding index into the IL PDB's sequence point arrays
2460     ULONG32 m_iSeqPoints;
2461
2462     MapIndexPair() : 
2463         m_iIlNativeMap((ULONG32) -1), 
2464         m_iSeqPoints((ULONG32) -1)
2465     {
2466         LIMITED_METHOD_CONTRACT;
2467     }
2468 };
2469
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.
2474 // 
2475 class QuickSortMapIndexPairsByNativeOffset : public CQuickSort<MapIndexPair>
2476 {
2477   public:
2478     QuickSortMapIndexPairsByNativeOffset(
2479         MapIndexPair * rgMap, 
2480         int cEntries, 
2481         ICorDebugInfo::OffsetMapping * rgIlNativeMap,
2482         ULONG32 cIlNativeMap)
2483         : CQuickSort<MapIndexPair>(rgMap, cEntries),
2484           m_rgIlNativeMap(rgIlNativeMap),
2485           m_cIlNativeMap(cIlNativeMap)
2486     {
2487         LIMITED_METHOD_CONTRACT;
2488     }
2489
2490     int Compare(MapIndexPair * pFirst,
2491                 MapIndexPair * pSecond)
2492     {
2493         LIMITED_METHOD_CONTRACT;
2494
2495         _ASSERTE(pFirst->m_iIlNativeMap < m_cIlNativeMap);
2496         _ASSERTE(pSecond->m_iIlNativeMap < m_cIlNativeMap);
2497
2498         DWORD dwFirstNativeOffset = m_rgIlNativeMap[pFirst->m_iIlNativeMap].nativeOffset;
2499         DWORD dwSecondNativeOffset = m_rgIlNativeMap[pSecond->m_iIlNativeMap].nativeOffset;
2500
2501         if (dwFirstNativeOffset < dwSecondNativeOffset)
2502             return -1;
2503         else if (dwFirstNativeOffset == dwSecondNativeOffset)
2504             return 0;
2505         else
2506             return 1;
2507     }
2508
2509 protected:
2510     ICorDebugInfo::OffsetMapping * m_rgIlNativeMap;
2511     ULONG32 m_cIlNativeMap;
2512 };
2513
2514 // ----------------------------------------------------------------------------
2515 // The following 3 classes contain the code to generate PDBs
2516 // 
2517
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
2520 enum PDBExtraData
2521 {
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,
2525 };
2526
2527
2528 // ----------------------------------------------------------------------------
2529 // Manages generating all PDB data for an NGENd image.  One of these is instantiated per
2530 // run of "ngen createpdb"
2531 // 
2532 class NGenPdbWriter
2533 {
2534 private:
2535     CreateNGenPdbWriter_t m_Create;
2536     HMODULE m_hModule;
2537     ReleaseHolder<ISymUnmanagedBinder> m_pBinder;
2538     LPCWSTR m_wszPdbPath;
2539     DWORD m_dwExtraData;
2540     LPCWSTR m_wszManagedPDBSearchPath;
2541
2542 public:
2543     NGenPdbWriter (LPCWSTR wszNativeImagePath, LPCWSTR wszPdbPath, DWORD dwExtraData, LPCWSTR wszManagedPDBSearchPath)
2544         : m_Create(NULL),
2545           m_hModule(NULL),
2546           m_wszPdbPath(wszPdbPath),
2547           m_dwExtraData(dwExtraData),
2548           m_wszManagedPDBSearchPath(wszManagedPDBSearchPath)
2549     {
2550         LIMITED_METHOD_CONTRACT;
2551     }
2552
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")
2554
2555     HRESULT Load(LPCWSTR wszDiasymreaderPath = nullptr)
2556     {
2557         STANDARD_VM_CONTRACT;
2558
2559         HRESULT hr = S_OK;
2560
2561         m_hModule = WszLoadLibrary(wszDiasymreaderPath != nullptr ? wszDiasymreaderPath : (LPCWSTR)NATIVE_SYMBOL_READER_DLL);
2562         if (m_hModule == NULL)
2563         {
2564             hr = HRESULT_FROM_WIN32(GetLastError());
2565             GetSvcLogger()->Printf(WRITER_LOAD_ERROR_MESSAGE, GetLastError());
2566             return hr;
2567         }
2568
2569         m_Create = reinterpret_cast<CreateNGenPdbWriter_t>(GetProcAddress(m_hModule, "CreateNGenPdbWriter"));
2570         if (m_Create == NULL)
2571         {
2572             hr = HRESULT_FROM_WIN32(GetLastError());
2573             GetSvcLogger()->Printf(WRITER_LOAD_ERROR_MESSAGE, GetLastError());
2574             return hr;
2575         }
2576
2577         if ((m_dwExtraData & kPDBLines) != 0)
2578         {
2579             hr = FakeCoCreateInstanceEx(
2580                 CLSID_CorSymBinder_SxS,
2581                 wszDiasymreaderPath != nullptr ? wszDiasymreaderPath : (LPCWSTR)NATIVE_SYMBOL_READER_DLL,
2582                 IID_ISymUnmanagedBinder,
2583                 (void**)&m_pBinder,
2584                 NULL);
2585         }
2586
2587         return hr;
2588     }
2589
2590     HRESULT WritePDBDataForModule(Module * pModule);
2591
2592     ~NGenPdbWriter()
2593     {
2594         LIMITED_METHOD_CONTRACT;
2595
2596         if (m_hModule)
2597             FreeLibrary(m_hModule);
2598
2599         m_Create = NULL;
2600     }
2601 };
2602
2603 #define UNKNOWN_SOURCE_FILE_PATH W("unknown")
2604
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.
2610 // 
2611 class NGenModulePdbWriter
2612 {
2613 private:
2614     // Simple holder to coordinate the PDB calls to OpenModW and CloseMod on a given PDB
2615     // Mod *.
2616     class PDBModHolder
2617     {
2618     private:
2619         ReleaseHolder<ISymNGenWriter2> m_pWriter;
2620         LPBYTE m_pMod;
2621
2622     public:
2623         PDBModHolder()
2624             : m_pWriter(NULL),
2625               m_pMod(NULL)
2626         {
2627             LIMITED_METHOD_CONTRACT;
2628         }
2629
2630         ~PDBModHolder()
2631         {
2632             LIMITED_METHOD_CONTRACT;
2633
2634             if ((m_pWriter != NULL) && (m_pMod != NULL))
2635             {
2636                 m_pWriter->CloseMod(m_pMod);
2637             }
2638         }
2639
2640         HRESULT Open(ISymNGenWriter2 * pWriter, LPCWSTR wszModule, LPCWSTR wszObjFile)
2641         {
2642             LIMITED_METHOD_CONTRACT;
2643
2644             _ASSERTE(m_pWriter == NULL);
2645
2646             m_pWriter = pWriter;
2647             m_pWriter->AddRef();
2648
2649             _ASSERTE(m_pMod == NULL);
2650
2651             HRESULT hr = m_pWriter->OpenModW(wszModule, wszObjFile, &m_pMod);
2652             if (FAILED(hr))
2653             {
2654                 m_pMod = NULL;
2655             }
2656             return hr;
2657         }
2658
2659         LPBYTE GetModPtr()
2660         {
2661             LIMITED_METHOD_CONTRACT;
2662
2663             _ASSERTE(m_pMod != NULL);
2664             return m_pMod;
2665         }
2666     };
2667
2668 private:
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.
2673     // 
2674     //************* NOTE! *************
2675     // 
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;
2683     // 
2684     // ************* NOTE! *************
2685     
2686     CreateNGenPdbWriter_t m_Create;
2687     LPCWSTR m_wszPdbPath;
2688     ReleaseHolder<ISymNGenWriter2> m_pWriter;
2689     Module * m_pModule;
2690     DWORD m_dwExtraData;
2691     LPCWSTR m_wszManagedPDBSearchPath;
2692
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;
2699
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;
2711
2712     // Keeps track of source file names and how they map to offsets in the relevant PDB
2713     // subsections.
2714     DocNameToOffsetMap m_docNameToOffsetMap;
2715
2716     // Holds a PDB Mod *
2717     PDBModHolder m_pdbMod;
2718
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;
2723
2724     HRESULT InitILPdbData();
2725     HRESULT WriteStringTable();
2726     HRESULT WriteFileChecksums();
2727
2728 public:
2729     NGenModulePdbWriter(CreateNGenPdbWriter_t Create, LPCWSTR wszPdbPath, DWORD dwExtraData, ISymUnmanagedBinder * pBinder, Module * pModule, LPCWSTR wszManagedPDBSearchPath)
2730         : m_Create(Create),
2731           m_wszPdbPath(wszPdbPath),
2732           m_pWriter(NULL),
2733           m_pModule(pModule),
2734           m_dwExtraData(dwExtraData),
2735           m_wszManagedPDBSearchPath(wszManagedPDBSearchPath),
2736           m_pBinder(pBinder),
2737           m_ilPdbDocCount(0),
2738           m_finalPdbDocCount(1)
2739     {
2740         LIMITED_METHOD_CONTRACT;
2741
2742         if (m_pBinder != NULL)
2743             m_pBinder->AddRef();
2744
2745         ZeroMemory(m_wszPDBFilePath, sizeof(m_wszPDBFilePath));
2746     }
2747
2748         ~NGenModulePdbWriter();
2749     
2750     HRESULT WritePDBData();
2751
2752     HRESULT WriteMethodPDBData(PEImageLayout * pLoadedLayout, USHORT iCodeSection, BYTE *pCodeBase, MethodDesc * hotDesc, PCODE start, bool isILPDBProvided);
2753 };
2754
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.
2759 // 
2760 class NGenMethodLinesPdbWriter
2761 {
2762 private:
2763     ISymNGenWriter2 * m_pWriter;
2764     LPBYTE m_pMod;
2765     ISymUnmanagedReader * m_pReader;
2766     MethodDesc * m_hotDesc;
2767     PCODE m_start;
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;
2774
2775     // IL-to-native map from JIT manager
2776     ULONG32 m_cIlNativeMap;
2777     NewArrayHolder<ICorDebugInfo::OffsetMapping> m_rgIlNativeMap;
2778
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
2784
2785     HRESULT WriteNativeILMapPDBData();
2786     LPBYTE InitDebugLinesHeaderSection(
2787         DEBUG_S_SUBSECTION_TYPE type,
2788         ULONG32 ulCodeStartOffset,
2789         ULONG32 cbCode,
2790         ULONG32 lineSize,
2791         CV_DebugSSubsectionHeader_t **ppSubSectHeader /*out*/,
2792         CV_DebugSLinesHeader_t ** ppLinesHeader /*out*/,
2793         LPBYTE * ppbLinesSubsectionCur /*out*/);
2794
2795     HRESULT WriteDebugSLinesSubsection(
2796         ULONG32 ulCodeStartOffset,
2797         ULONG32 cbCode,
2798         MapIndexPair * rgMapIndexPairs,
2799         ULONG32 cMapIndexPairs);
2800
2801     HRESULT WriteDebugSILLinesSubsection(
2802         ULONG32 ulCodeStartOffset,
2803         ULONG32 cbCode,
2804         ICorDebugInfo::OffsetMapping * rgILNativeMap,
2805         ULONG32 rgILNativeMapAdjustSize);
2806
2807     BOOL FinalizeLinesFileBlock(
2808         CV_DebugSLinesFileBlockHeader_t * pLinesFileBlockHeader,
2809         CV_Line_t * pLineBlockStart,
2810         CV_Line_t * pLineBlockAfterEnd
2811 #ifdef _DEBUG
2812         , BOOL ignorekUnmappedIPCheck = false
2813 #endif
2814         );
2815
2816 public:
2817     NGenMethodLinesPdbWriter(
2818         ISymNGenWriter2 * pWriter,
2819         LPBYTE pMod,
2820         ISymUnmanagedReader * pReader,
2821         MethodDesc * hotDesc,
2822         PCODE start, 
2823         USHORT iCodeSection, 
2824         TADDR addrCodeSection,
2825         const IJitManager::MethodRegionInfo * pMethodRegionInfo,
2826         EECodeInfo * pCodeInfo,
2827         DocNameToOffsetMap * pDocNameToOffsetMap,
2828         bool isILPDBProvided)
2829         : m_pWriter(pWriter),
2830           m_pMod(pMod),
2831           m_pReader(pReader),
2832           m_hotDesc(hotDesc),
2833           m_start(start),
2834           m_iCodeSection(iCodeSection),
2835           m_addrCodeSection(addrCodeSection),
2836           m_pMethodRegionInfo(pMethodRegionInfo),
2837           m_pCodeInfo(pCodeInfo),
2838           m_pDocNameToOffsetMap(pDocNameToOffsetMap),
2839           m_isILPDBProvided(isILPDBProvided),
2840           m_cIlNativeMap(0),
2841           m_cSeqPoints(0)
2842     {
2843         LIMITED_METHOD_CONTRACT;
2844     }
2845
2846     HRESULT WritePDBData();
2847 };
2848
2849 // ----------------------------------------------------------------------------
2850 // NGenPdbWriter implementation
2851
2852
2853
2854 //---------------------------------------------------------------------------------------
2855 //
2856 // Coordinates calling all the other classes & methods to generate PDB info for the
2857 // given Module
2858 //
2859 // Arguments:
2860 //      pModule - EE Module to write PDB data for
2861 //
2862
2863 HRESULT NGenPdbWriter::WritePDBDataForModule(Module * pModule)
2864 {
2865     STANDARD_VM_CONTRACT;
2866     NGenModulePdbWriter ngenModulePdbWriter(m_Create, m_wszPdbPath, m_dwExtraData, m_pBinder, pModule, m_wszManagedPDBSearchPath);
2867     return ngenModulePdbWriter.WritePDBData();
2868 }
2869
2870
2871 // ----------------------------------------------------------------------------
2872 // NGenModulePdbWriter implementation
2873
2874
2875 //---------------------------------------------------------------------------------------
2876 //
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.
2880 // 
2881 HRESULT NGenModulePdbWriter::WriteStringTable()
2882 {
2883     STANDARD_VM_CONTRACT;
2884
2885     _ASSERTE(m_pWriter != NULL);
2886
2887     HRESULT hr;
2888     UINT64 cbStringTableEstimate =
2889         sizeof(DWORD) +
2890         sizeof(CV_DebugSSubsectionHeader_t) +
2891         m_finalPdbDocCount * (MAX_LONGPATH + 1);
2892     if (!FitsIn<ULONG32>(cbStringTableEstimate))
2893     {
2894         return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
2895     }
2896     
2897     m_rgbStringTableSubsection = new BYTE[ULONG32(cbStringTableEstimate)];
2898     LPBYTE pbStringTableSubsectionCur = m_rgbStringTableSubsection;
2899
2900     // Subsection signature
2901     *((DWORD *) pbStringTableSubsectionCur) = CV_SIGNATURE_C13;
2902     pbStringTableSubsectionCur += sizeof(DWORD);
2903
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
2912
2913     LPBYTE pbStringTableStart = pbStringTableSubsectionCur;
2914
2915     // The actual strings
2916     for (ULONG32 i = 0; i < m_finalPdbDocCount; i++)
2917     {
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;
2924         ULONG32 cchURL;
2925         if (i < m_ilPdbDocCount)
2926         {
2927             hr = m_rgpDocs[i]->GetURL(_countof(wszURL), &cchURL, wszURL);
2928             if (FAILED(hr))
2929                 return hr;
2930         }
2931         int cbWritten = WideCharToMultiByte(
2932             CP_UTF8,
2933             0,                                      // dwFlags
2934             wszURL,
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
2941             );
2942         if (cbWritten == 0)
2943             return HRESULT_FROM_WIN32(GetLastError());
2944
2945         // Remember the string table offset for later
2946         m_docNameToOffsetMap.AddOrReplace(
2947             (LPCSTR) pbStringTableSubsectionCur, 
2948             DocNameOffsets(
2949                 ULONG32(pbStringTableSubsectionCur - pbStringTableStart),
2950                 (ULONG32) -1));
2951         
2952         pbStringTableSubsectionCur += cbWritten;
2953         if (pbStringTableSubsectionCur >= (m_rgbStringTableSubsection + cbStringTableEstimate))
2954             return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
2955     }
2956
2957     // Now that we know pSubSectHeader->cbLen, fill it in
2958     pSubSectHeader->cbLen = CV_off32_t(pbStringTableSubsectionCur - pbStringTableStart);
2959
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));
2965     if (FAILED(hr))
2966         return hr;
2967
2968     return S_OK;
2969 }
2970
2971 //---------------------------------------------------------------------------------------
2972 //
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.
2975 // 
2976 HRESULT NGenModulePdbWriter::InitILPdbData()
2977 {
2978     // Load the managed PDB
2979     
2980     ReleaseHolder<IUnknown> pUnk = NULL;
2981     HRESULT hr = m_pModule->GetReadablePublicMetaDataInterface(ofReadOnly, IID_IMetaDataImport, (LPVOID *) &pUnk);
2982     if (FAILED(hr))
2983     {
2984         GetSvcLogger()->Printf(
2985             W("Unable to obtain metadata for '%s'  Error: '0x%x'.\n"),
2986             LPCWSTR(m_pModule->GetFile()->GetILimage()->GetPath()),
2987             hr);
2988         return hr;
2989     }
2990
2991     hr = m_pBinder->GetReaderForFile(
2992         pUnk,
2993         m_pModule->GetFile()->GetILimage()->GetPath(),
2994         m_wszManagedPDBSearchPath,
2995         &m_pReader);
2996     if (FAILED(hr))
2997     {
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));
3004         return hr;
3005     }
3006
3007     GetSvcLogger()->Log(W("Loaded managed PDB"));
3008
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),
3014         &cchIlPdbPath,
3015         wszIlPdbPath);
3016     if (FAILED(hr))
3017     {
3018         GetSvcLogger()->Log(W("\n"));
3019     }
3020     else
3021     {
3022         GetSvcLogger()->Printf(W(": '%s'\n"), wszIlPdbPath);
3023     }
3024
3025     // Read all source files names from the IL PDB
3026     ULONG32 cDocs;
3027     hr = m_pReader->GetDocuments(
3028         0,              // cDocsRequested
3029         &cDocs,
3030         NULL            // Array
3031         );
3032     if (FAILED(hr))
3033         return hr;
3034     
3035     m_rgpDocs = new ISymUnmanagedDocument * [cDocs];
3036     hr = m_pReader->GetDocuments(
3037         cDocs,
3038         &m_ilPdbDocCount,
3039         m_rgpDocs);
3040     if (FAILED(hr))
3041         return hr;
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);
3045     
3046     return S_OK;
3047 }
3048
3049 NGenModulePdbWriter::~NGenModulePdbWriter()
3050 {
3051         // Delete any temporary files we created. 
3052         if (m_tempSourceDllName.GetCount() != 0)
3053                 DeleteFileW(m_tempSourceDllName);
3054         m_tempSourceDllName.Clear();
3055 }
3056
3057 //---------------------------------------------------------------------------------------
3058 //
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
3061 // subsection
3062 // 
3063 HRESULT NGenModulePdbWriter::WritePDBData()
3064 {
3065     STANDARD_VM_CONTRACT;
3066
3067     _ASSERTE(m_pWriter == NULL);
3068
3069     HRESULT hr;
3070
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
3073     // on disk.
3074     bool isILPDBProvided = false;
3075     if ((m_dwExtraData & kPDBLines) != 0)
3076     {
3077         hr = InitILPdbData();
3078         if (FAILED(hr))
3079             return hr;
3080         isILPDBProvided = true;
3081     }
3082
3083     // Create the PDB file we will write into.
3084
3085     _ASSERTE(m_Create != NULL);
3086     _ASSERTE(m_pModule != NULL);
3087
3088     PEImageLayout * pLoadedLayout = m_pModule->GetFile()->GetLoaded();
3089
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")))
3098         {
3099                 SString::Iterator fileNameStart = dllPath.End();
3100                 dllPath.FindBack(fileNameStart, DIRECTORY_SEPARATOR_STR_W);
3101
3102                 SString::Iterator ext = dllPath.End();
3103                 dllPath.FindBack(ext, '.');
3104
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;
3112         }
3113
3114     ReleaseHolder<ISymNGenWriter> pWriter1;
3115     hr = m_Create(dllPath, m_wszPdbPath, &pWriter1);
3116     if (FAILED(hr))
3117         return hr;
3118     
3119     hr = pWriter1->QueryInterface(IID_ISymNGenWriter2, (LPVOID*) &m_pWriter);
3120     if (FAILED(hr))
3121     {
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"),
3124             hr);
3125         return hr;
3126     }
3127
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
3130
3131     hr = m_pWriter->QueryPDBNameExW(m_wszPDBFilePath, _countof(m_wszPDBFilePath));
3132     if (SUCCEEDED(hr))
3133     {
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);
3140     }
3141
3142
3143     hr = m_pdbMod.Open(m_pWriter, pLoadedLayout->GetPath(), m_pModule->GetPath());
3144     if (FAILED(hr))
3145         return hr;
3146
3147     hr = WriteStringTable();
3148     if (FAILED(hr))
3149         return hr;
3150
3151     hr = WriteFileChecksums();
3152     if (FAILED(hr))
3153         return hr;
3154     
3155
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) 
3162     {
3163         hr = m_pWriter->AddSection((USHORT)(sectionIndex + 1),
3164                                  OMF_StandardText, 
3165                                  0,
3166                                  section[sectionIndex].SizeOfRawData);
3167         if (FAILED(hr))
3168             return hr;
3169
3170         if (strcmp((const char *)&section[sectionIndex].Name[0], ".text") == 0) {
3171             _ASSERTE((iCodeSection == 0) && (pCodeBase == NULL));
3172             iCodeSection = (USHORT)(sectionIndex + 1);
3173             pCodeBase = (BYTE *)section[sectionIndex].VirtualAddress;
3174         }
3175
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
3178         // section we add.
3179         hr = m_pWriter->ModAddSecContribEx(
3180             m_pdbMod.GetModPtr(),
3181             (USHORT)(sectionIndex + 1),
3182             0,
3183             section[sectionIndex].SizeOfRawData,
3184             section[sectionIndex].Characteristics,
3185             0,          // dwDataCrc
3186             0           // dwRelocCrc
3187             );
3188         if (FAILED(hr))
3189             return hr;
3190
3191         sectionIndex++;
3192     }
3193
3194     _ASSERTE(iCodeSection != 0);
3195     _ASSERTE(pCodeBase != NULL);
3196
3197
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
3201         OMF_SentinelType, 
3202         0,
3203         0xFFFFffff);
3204     if (FAILED(hr))
3205         return hr;
3206     
3207
3208 #ifdef FEATURE_READYTORUN_COMPILER
3209     if (pLoadedLayout->HasReadyToRunHeader())
3210     {
3211         ReadyToRunInfo::MethodIterator mi(m_pModule->GetReadyToRunInfo());
3212         while (mi.Next())
3213         {
3214             MethodDesc *hotDesc = mi.GetMethodDesc();
3215
3216             hr = WriteMethodPDBData(pLoadedLayout, iCodeSection, pCodeBase, hotDesc, mi.GetMethodStartAddress(), isILPDBProvided);
3217             if (FAILED(hr))
3218                 return hr;
3219         }
3220     }
3221     else
3222 #endif // FEATURE_READYTORUN_COMPILER
3223     {
3224         MethodIterator mi(m_pModule);
3225         while (mi.Next()) 
3226         {
3227             MethodDesc *hotDesc = mi.GetMethodDesc();
3228             hotDesc->CheckRestore();
3229
3230             hr = WriteMethodPDBData(pLoadedLayout, iCodeSection, pCodeBase, hotDesc, mi.GetMethodStartAddress(), isILPDBProvided);
3231             if (FAILED(hr))
3232                 return hr;
3233         }
3234     }
3235
3236     // We made it successfully to the end, so don't delete the PDB file.
3237     m_deletePDBFileHolder.SuppressRelease();
3238     return S_OK;
3239 }
3240
3241 HRESULT NGenModulePdbWriter::WriteMethodPDBData(PEImageLayout * pLoadedLayout, USHORT iCodeSection, BYTE *pCodeBase, MethodDesc * hotDesc, PCODE start, bool isILPDBProvided)
3242 {
3243     STANDARD_VM_CONTRACT;
3244
3245     HRESULT hr;
3246
3247     EECodeInfo codeInfo(start);
3248     _ASSERTE(codeInfo.IsValid());
3249
3250     IJitManager::MethodRegionInfo methodRegionInfo;
3251     codeInfo.GetMethodRegionInfo(&methodRegionInfo);
3252
3253     PCODE pHotCodeStart = methodRegionInfo.hotStartAddress;
3254     _ASSERTE(pHotCodeStart);
3255
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());
3263
3264     // Hot name
3265     {
3266         SString fullName;
3267         TypeString::AppendMethodInternal(
3268             fullName, 
3269             hotDesc, 
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,
3278                                 iCodeSection,
3279                                 (pHotCodeStart - (TADDR)pLoadedLayout->GetBase() - (TADDR)pCodeBase));
3280         if (FAILED(hr))
3281             return hr;
3282     }
3283
3284     // Cold name
3285     {
3286         if (pColdCodeStart) {
3287
3288             SString fullNameCold;
3289             fullNameCold.Append(W("[COLD] "));
3290             TypeString::AppendMethodInternal(
3291                 fullNameCold, 
3292                 hotDesc, 
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);
3299
3300             BSTRHolder coldNameHolder(SysAllocString(fullNameCold.GetUnicode()));
3301             hr = m_pWriter->AddSymbol(coldNameHolder,
3302                                     iCodeSection,
3303                                     (pColdCodeStart - (TADDR)pLoadedLayout->GetBase() - (TADDR)pCodeBase));
3304                 
3305             if (FAILED(hr))
3306                 return hr;
3307
3308         }
3309     }
3310
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))
3315     {
3316         NGenMethodLinesPdbWriter methodLinesWriter(
3317             m_pWriter,
3318             m_pdbMod.GetModPtr(),
3319             m_pReader,
3320             hotDesc, 
3321             start, 
3322             iCodeSection, 
3323             (TADDR)pLoadedLayout->GetBase() + (TADDR)pCodeBase, 
3324             &methodRegionInfo, 
3325             &codeInfo, 
3326             &m_docNameToOffsetMap,
3327             isILPDBProvided);
3328
3329         hr = methodLinesWriter.WritePDBData();
3330         if (FAILED(hr))
3331             return hr;
3332     }
3333
3334     return S_OK;
3335 }
3336
3337 // ----------------------------------------------------------------------------
3338 // Handles writing the file checksums subsection to the PDB
3339 // 
3340 HRESULT NGenModulePdbWriter::WriteFileChecksums()
3341 {
3342     STANDARD_VM_CONTRACT;
3343
3344     _ASSERTE(m_pWriter != NULL);
3345
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:
3348     // 
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
3355     //     
3356     HRESULT hr;
3357
3358     // PDB format requires that the checksum size can always be expressed in a BYTE.
3359     const BYTE kcbEachChecksumEstimate = 0xFF;
3360
3361     UINT64 cbChecksumSubsectionEstimate =
3362         sizeof(DWORD) +
3363         sizeof(CV_DebugSSubsectionHeader_t) +
3364         m_finalPdbDocCount * kcbEachChecksumEstimate;
3365     if (!FitsIn<ULONG32>(cbChecksumSubsectionEstimate))
3366     {
3367         return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
3368     }
3369
3370     NewArrayHolder<BYTE> rgbChksumSubsection(new BYTE[ULONG32(cbChecksumSubsectionEstimate)]);
3371     LPBYTE pbChksumSubsectionCur = rgbChksumSubsection;
3372
3373     // (1) Subsection signature
3374     *((DWORD *) pbChksumSubsectionCur) = CV_SIGNATURE_C13;
3375     pbChksumSubsectionCur += sizeof(DWORD);
3376
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
3383
3384     LPBYTE pbChksumDataStart = pbChksumSubsectionCur;
3385
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++)
3389     {
3390         WCHAR wszURL[MAX_LONGPATH] = UNKNOWN_SOURCE_FILE_PATH;
3391         char szURL[MAX_LONGPATH];
3392         ULONG32 cchURL;
3393
3394
3395         bool isKnownSourcePath = i < m_ilPdbDocCount;
3396         if (isKnownSourcePath)
3397         {
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);
3404             if (FAILED(hr))
3405                 return hr;
3406         }
3407
3408         int cbWritten = WideCharToMultiByte(
3409             CP_UTF8,
3410             0,                                      // dwFlags
3411             wszURL,
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
3417             );
3418         if (cbWritten == 0)
3419             return HRESULT_FROM_WIN32(GetLastError());
3420
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)
3426         {
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;
3430         }
3431         DocNameOffsets docNameOffsets(pMapEntry->Value());
3432         docNameOffsets.m_dwChksumTableOffset = ULONG32(pbChksumSubsectionCur - pbChksumDataStart);
3433
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);
3442
3443         // Checksum algorithm and bytes
3444
3445         BYTE rgbChecksum[kcbEachChecksumEstimate];
3446         ULONG32 cbChecksum = 0;
3447         BYTE bChecksumAlgorithmType = CHKSUM_TYPE_NONE;
3448         if (isKnownSourcePath)
3449         {
3450             GUID guidChecksumAlgorithm;
3451             hr = m_rgpDocs[i]->GetCheckSumAlgorithmId(&guidChecksumAlgorithm);
3452             if (SUCCEEDED(hr))
3453             {
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;
3460             }
3461         }
3462
3463         if (bChecksumAlgorithmType != CHKSUM_TYPE_NONE)
3464         {
3465             hr = m_rgpDocs[i]->GetCheckSum(sizeof(rgbChecksum), &cbChecksum, rgbChecksum);
3466             if (FAILED(hr) || !FitsIn<BYTE>(cbChecksum))
3467             {
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;
3471                 cbChecksum = 0;
3472             }
3473         }
3474
3475         // checksum length & algorithm
3476         *pbChksumSubsectionCur = (BYTE) cbChecksum;             
3477         pbChksumSubsectionCur++;
3478         *pbChksumSubsectionCur = bChecksumAlgorithmType;
3479         pbChksumSubsectionCur++;
3480
3481         // checksum data bytes
3482         memcpy(pbChksumSubsectionCur, rgbChecksum, cbChecksum);
3483         pbChksumSubsectionCur += cbChecksum;
3484
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;
3489     }
3490
3491     // Now that we know pSubSectHeader->cbLen, fill it in
3492     pSubSectHeader->cbLen = CV_off32_t(pbChksumSubsectionCur - pbChksumDataStart);
3493
3494     // Subsection is now filled out, so add it
3495     hr = m_pWriter->ModAddSymbols(
3496         m_pdbMod.GetModPtr(), 
3497         rgbChksumSubsection, 
3498         int(pbChksumSubsectionCur - rgbChksumSubsection));
3499     if (FAILED(hr))
3500         return hr;
3501
3502     return S_OK;
3503 }
3504
3505 // ----------------------------------------------------------------------------
3506 // NGenMethodLinesPdbWriter implementation
3507
3508
3509 //---------------------------------------------------------------------------------------
3510 //
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.
3514 //
3515
3516 HRESULT NGenMethodLinesPdbWriter::WritePDBData()
3517 {
3518     STANDARD_VM_CONTRACT;
3519
3520     if (m_hotDesc->IsNoMetadata())
3521     {
3522         // IL stubs will not have data in the IL PDB, so just skip them.
3523         return S_OK;
3524     }
3525
3526     //
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
3530     // 
3531
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(
3536         debugInfoRequest,
3537         SimpleNew, NULL,            // Allocator
3538         &m_cIlNativeMap,
3539         &m_rgIlNativeMap,
3540         NULL, NULL);
3541     if (!fSuccess)
3542     {
3543         // Shouldn't happen, but just skip this method if it does
3544         return S_OK;
3545     }
3546     HRESULT hr;
3547     if (FAILED(hr = WriteNativeILMapPDBData()))
3548     {
3549         return hr;
3550     }
3551
3552     if (!m_isILPDBProvided)
3553     {
3554         return S_OK;
3555     }
3556
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);
3561     sorterByIl.Sort();
3562
3563     // Now grab IL-to-source map from the IL PDBs (just known as "sequence points"
3564     // according to the IL PDB API)
3565     
3566     ReleaseHolder<ISymUnmanagedMethod> pMethod;
3567     hr = m_pReader->GetMethod(
3568         m_hotDesc->GetMemberDef(),
3569         &pMethod);
3570     if (FAILED(hr))
3571     {
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).
3575         return S_OK;
3576     }
3577
3578     ULONG32 cSeqPointsExpected;
3579     hr = pMethod->GetSequencePointCount(&cSeqPointsExpected);
3580     if (FAILED(hr))
3581     {
3582         // Should never happen, but we can just skip this function if the IL PDB can't
3583         // find sequence point info
3584         return S_OK;
3585     }
3586
3587     ULONG32 cSeqPointsReturned;
3588     m_rgilOffsets = new ULONG32[cSeqPointsExpected];
3589     m_rgpDocs = new ISymUnmanagedDocument * [cSeqPointsExpected];
3590     m_rgnLineStarts = new ULONG32[cSeqPointsExpected];
3591     
3592     //  This is guaranteed to return the sequence points sorted in order of the IL
3593     //  offsets (m_rgilOffsets)
3594     hr = pMethod->GetSequencePoints(
3595         cSeqPointsExpected,
3596         &cSeqPointsReturned,
3597         m_rgilOffsets,
3598         m_rgpDocs,
3599         m_rgnLineStarts,
3600         NULL,       // ColumnStarts not needed
3601         NULL,       // LineEnds not needed
3602         NULL);      // ColumnEnds not needed
3603     if (FAILED(hr))
3604     {
3605         // Shouldn't happen, but just skip this method if it does
3606         return S_OK;
3607     }
3608     // Commit m_rgpDocs to calling Release() on all ISymUnmanagedDocument* returned into
3609     // the array.
3610     m_rgpDocs.SetElementCount(cSeqPointsReturned);
3611
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;
3621
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;
3629     
3630     ULONG32 iIlNativeMap = 0;
3631     ULONG32 iMapIndexPairs = 0;
3632         
3633     // Traverse IL PDB entries and IL-to-native map entries (both sorted by IL) in
3634     // parallel
3635     // 
3636     //     * Record matching indices in our output map, rgMapIndexPairs, indexed by
3637     //         iMapIndexPairs.
3638     // 
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.)
3643     // 
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)
3649     {
3650         _ASSERTE (iMapIndexPairs < cMapIndexPairsMax);
3651
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))
3657         {
3658             rgMapIndexPairs[iMapIndexPairs].m_iIlNativeMap = iIlNativeMap;
3659             rgMapIndexPairs[iMapIndexPairs].m_iSeqPoints = kUnmappedIP;
3660             iMapIndexPairs++;
3661
3662             // If we were remembering a prior unmatched entry in the IL PDB, reset it
3663             iSeqPointLastUnmatched = (ULONG32) -1;
3664
3665             // Advance il-native map, NOT il-source map
3666             iIlNativeMap++;
3667             continue;
3668         }
3669
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)
3673             break;
3674
3675         if (m_rgIlNativeMap[iIlNativeMap].ilOffset < m_rgilOffsets[iSeqPoints])
3676         {
3677             // Our cursor over the ilnative map is behind the sourceil
3678             // map
3679             
3680             if (iSeqPointLastUnmatched != (ULONG32) -1)
3681             {
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;
3691                 iMapIndexPairs++;
3692                 
3693                 // Reset our memory of the last unmatched entry in the IL PDB
3694                 iSeqPointLastUnmatched = (ULONG32) -1;
3695             }
3696                         else if (iMapIndexPairs > 0)
3697                         {
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)
3701                                 {
3702                                         rgMapIndexPairs[iMapIndexPairs - 1].m_iIlNativeMap = iIlNativeMap;
3703                                 }
3704
3705                         }
3706             // Go to next ilnative map entry
3707             iIlNativeMap++;
3708             continue;
3709         }
3710
3711         if (m_rgilOffsets[iSeqPoints] < m_rgIlNativeMap[iIlNativeMap].ilOffset)
3712         {
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)
3717             {
3718                 iSeqPointLastUnmatched = iSeqPoints;
3719             }
3720             iSeqPoints++;
3721             fCurSeqPointMatched = FALSE;
3722             continue;
3723         }
3724
3725         // At a match
3726         _ASSERTE(m_rgilOffsets[iSeqPoints] == m_rgIlNativeMap[iIlNativeMap].ilOffset);
3727         rgMapIndexPairs[iMapIndexPairs].m_iIlNativeMap = iIlNativeMap;
3728         rgMapIndexPairs[iMapIndexPairs].m_iSeqPoints = iSeqPoints;
3729         
3730         // If we were remembering a prior unmatched entry in the IL PDB, reset it
3731         iSeqPointLastUnmatched = (ULONG32) -1;
3732         
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
3736         iMapIndexPairs++;
3737         iIlNativeMap++;
3738         fCurSeqPointMatched = TRUE;
3739     }
3740
3741     ULONG32 cMapIndexPairs = iMapIndexPairs;
3742
3743     // PDB format requires the lines array to be sorted by IP offset
3744     QuickSortMapIndexPairsByNativeOffset sorterByIp(rgMapIndexPairs, cMapIndexPairs, m_rgIlNativeMap, m_cIlNativeMap);
3745     sorterByIp.Sort();
3746
3747     //
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
3751     // 
3752
3753     // Find the point where the code got split
3754     ULONG32 iMapIndexPairsFirstEntryInColdSection = cMapIndexPairs;
3755     for (iMapIndexPairs = 0; iMapIndexPairs < cMapIndexPairs; iMapIndexPairs++)
3756     {
3757         DWORD dwNativeOffset = m_rgIlNativeMap[rgMapIndexPairs[iMapIndexPairs].m_iIlNativeMap].nativeOffset;
3758         if (dwNativeOffset >= m_pMethodRegionInfo->hotSize)
3759         {
3760             iMapIndexPairsFirstEntryInColdSection = iMapIndexPairs;
3761             break;
3762         }
3763     }
3764
3765     // Adjust the cold offsets (if any) to be relative to the cold start
3766     for (iMapIndexPairs = iMapIndexPairsFirstEntryInColdSection; iMapIndexPairs < cMapIndexPairs; iMapIndexPairs++)
3767     {
3768         DWORD dwNativeOffset = m_rgIlNativeMap[rgMapIndexPairs[iMapIndexPairs].m_iIlNativeMap].nativeOffset;
3769         _ASSERTE (dwNativeOffset >= m_pMethodRegionInfo->hotSize);
3770
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;
3775     }
3776
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),
3781         rgMapIndexPairs,
3782         iMapIndexPairsFirstEntryInColdSection);
3783     if (FAILED(hr))
3784         return hr;
3785     
3786     // If there was a hot/cold split, write a separate lines-file subsection for the cold
3787     // region
3788     if (iMapIndexPairsFirstEntryInColdSection < cMapIndexPairs)
3789     {
3790         hr = WriteDebugSLinesSubsection(
3791             ULONG32(m_pMethodRegionInfo->coldStartAddress - m_addrCodeSection),
3792             ULONG32(m_pMethodRegionInfo->coldSize),
3793             &rgMapIndexPairs[iMapIndexPairsFirstEntryInColdSection],
3794             cMapIndexPairs - iMapIndexPairsFirstEntryInColdSection);
3795         if (FAILED(hr))
3796             return hr;
3797     }
3798
3799     return S_OK;
3800 }
3801
3802 //---------------------------------------------------------------------------------------
3803 //
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 
3806 // map this time.  
3807 //
3808
3809 HRESULT NGenMethodLinesPdbWriter::WriteNativeILMapPDBData()
3810 {
3811     STANDARD_VM_CONTRACT;
3812
3813     HRESULT hr;
3814
3815     QuickSortILNativeMapByNativeOffset sorterByNativeOffset(m_rgIlNativeMap, m_cIlNativeMap);
3816     sorterByNativeOffset.Sort();
3817
3818     ULONG32 iIlNativeMap = 0;
3819     ULONG32 ilNativeMapFirstEntryInColdeSection = m_cIlNativeMap;
3820     for (iIlNativeMap = 0; iIlNativeMap < m_cIlNativeMap; iIlNativeMap++)
3821     {
3822         if (m_rgIlNativeMap[iIlNativeMap].nativeOffset >= m_pMethodRegionInfo->hotSize)
3823         {
3824             ilNativeMapFirstEntryInColdeSection = iIlNativeMap;
3825             break;
3826         }
3827     }
3828
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++)
3832     {
3833         DWORD dwNativeOffset = m_rgIlNativeMap[iIlNativeMap].nativeOffset;
3834         _ASSERTE(dwNativeOffset >= m_pMethodRegionInfo->hotSize);
3835
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;
3842     }
3843
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),
3848         m_rgIlNativeMap,
3849         ilNativeMapFirstEntryInColdeSection);
3850     if (FAILED(hr))
3851         return hr;
3852
3853     // If there was a hot/cold split, write a separate lines-file subsection for the cold
3854     // region
3855     if (ilNativeMapFirstEntryInColdeSection < m_cIlNativeMap)
3856     {
3857         hr = WriteDebugSILLinesSubsection(
3858             ULONG32(m_pMethodRegionInfo->coldStartAddress - m_addrCodeSection),
3859             ULONG32(m_pMethodRegionInfo->coldSize),
3860             coldRgIlNativeMap,
3861             m_cIlNativeMap - ilNativeMapFirstEntryInColdeSection);
3862         if (FAILED(hr))
3863             return hr;
3864     }
3865
3866     return S_OK;
3867 }
3868
3869
3870 //---------------------------------------------------------------------------------------
3871 //
3872 // Helper called by NGenMethodLinesPdbWriter::WriteDebugSLinesSubsection and 
3873 // NGenMethodLinesPdbWriter::WriteDebugSILLinesSubsection to initial the DEBUG_S*_LINE 
3874 // subsection headers.
3875 //
3876 // Arguments:
3877 //      * ulCodeStartOffset - Offset relative to the code section, or where this region
3878 //          of code begins
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
3885 //
3886 // Return Value:
3887 //      * Pointer which points the staring address of the SubSection.
3888 //
3889
3890 LPBYTE NGenMethodLinesPdbWriter::InitDebugLinesHeaderSection(
3891     DEBUG_S_SUBSECTION_TYPE type,
3892     ULONG32 ulCodeStartOffset,
3893     ULONG32 cbCode,
3894     ULONG32 lineSize,
3895     CV_DebugSSubsectionHeader_t **ppSubSectHeader /*out*/,
3896     CV_DebugSLinesHeader_t ** ppLinesHeader /*out*/,
3897     LPBYTE * ppbLinesSubsectionCur /*out*/)
3898 {
3899     STANDARD_VM_CONTRACT;
3900
3901     UINT64 cbLinesSubsectionEstimate =
3902         sizeof(DWORD) +
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))
3909     {
3910         return NULL;
3911     }
3912
3913     LPBYTE rgbLinesSubsection = new BYTE[ULONG32(cbLinesSubsectionEstimate)];
3914     LPBYTE pbLinesSubsectionCur = rgbLinesSubsection;
3915
3916     // * (1) DWORD = CV_SIGNATURE_C13 -- the usual subsection signature DWORD
3917     *((DWORD *)pbLinesSubsectionCur) = CV_SIGNATURE_C13;
3918     pbLinesSubsectionCur += sizeof(DWORD);
3919
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);
3927
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;
3939 }
3940
3941 //---------------------------------------------------------------------------------------
3942 //
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.
3947 //
3948 // Arguments:
3949 //      * ulCodeStartOffset - Offset relative to the code section, or where this region
3950 //          of code begins
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.
3956 //
3957 // Assumptions:
3958 //      rgMapIndexPairs must be sorted in order of nativeOffset, i.e.,
3959 //      m_rgIlNativeMap[rgMapIndexPairs[i].m_iIlNativeMap].nativeOffset increases with i.
3960 //
3961
3962 HRESULT NGenMethodLinesPdbWriter::WriteDebugSLinesSubsection(
3963     ULONG32 ulCodeStartOffset,
3964     ULONG32 cbCode,
3965     MapIndexPair * rgMapIndexPairs,
3966     ULONG32 cMapIndexPairs)
3967 {
3968     STANDARD_VM_CONTRACT;
3969
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:
3972     // 
3973     // * (1) DWORD = CV_SIGNATURE_C13 -- the usual subsection signature DWORD
3974     // * (2) CV_DebugSSubsectionHeader_t -- the usual subsection header, with type =
3975     //     DEBUG_S_LINES
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.
3986
3987     HRESULT hr;
3988
3989
3990     CV_DebugSSubsectionHeader_t * pSubSectHeader = NULL;
3991     CV_DebugSLinesHeader_t * pLinesHeader = NULL;
3992     CV_DebugSLinesFileBlockHeader_t * LinesFileBlockHeader = NULL;
3993
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(
4000         DEBUG_S_LINES,
4001         ulCodeStartOffset,
4002         cbCode,
4003         cMapIndexPairs,
4004         &pSubSectHeader,
4005         &pLinesHeader,
4006         &pbLinesSubsectionCur);
4007
4008     if (pbLinesSubsectionCur == NULL)
4009     {
4010         return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
4011     }
4012
4013     NewArrayHolder<BYTE> rgbLinesSubsection(prgbLinesSubsection);
4014
4015     // The loop below takes care of
4016     //     * (4) CV_DebugSLinesFileBlockHeader_t
4017     //     * (5) CV_Line_t (Line array entries)
4018     //
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;
4031
4032     for (ULONG32 iMapIndexPairs=0; iMapIndexPairs < cMapIndexPairs; iMapIndexPairs++)
4033     {
4034         ULONG32 iSeqPoints = rgMapIndexPairs[iMapIndexPairs].m_iSeqPoints;
4035         ULONG32 iIlNativeMap = rgMapIndexPairs[iMapIndexPairs].m_iIlNativeMap;
4036
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)
4042         {
4043                         if (ilOffsetPrev == kUnmappedIP)
4044                         {
4045                                 // if the previous IL offset is kUnmappedIP, then we should rewrite it. 
4046                                 pLineCur = pLinePrev;
4047                         }
4048                         else if (iSeqPoints != kUnmappedIP &&
4049                                 m_rgilOffsets[iSeqPoints] < ilOffsetPrev)
4050                         {
4051                                 pLineCur = pLinePrev;
4052                         }
4053                         else
4054                         {
4055                                 // Found a native offset dupe, ignore the current map entry
4056                                 continue;
4057                         }
4058         }
4059
4060         if ((iSeqPoints != kUnmappedIP) && (iSeqPoints != iSeqPointsPrev))
4061         {
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];
4066             ULONG32 cchURL;
4067             hr = m_rgpDocs[iSeqPoints]->GetURL(_countof(wszURL), &cchURL, wszURL);
4068             if (FAILED(hr))
4069             {
4070                 // Skip function if IL PDB has data missing
4071                 return S_OK;
4072             }
4073
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)
4077             {
4078                 // New document.  Update wszURLPrev, and remember that we need to start a
4079                 // new file block
4080                 if (wcscpy_s(wszURLPrev, _countof(wszURLPrev), wszURL) != 0)
4081                 {
4082                     continue;
4083                 }
4084                 fBeginNewBlock = TRUE;
4085             }
4086
4087             iSeqPointsPrev = iSeqPoints;
4088         }
4089         if (fBeginNewBlock)
4090         {
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))
4094             {
4095                 fAtLeastOneBlockWritten = TRUE;
4096             }
4097             else if (pLinesFileBlockHeader != NULL)
4098             {
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;
4103             }
4104
4105             // Now get the info we'll need for the next block
4106             char szURL[MAX_LONGPATH];
4107             int cbWritten = WideCharToMultiByte(
4108                 CP_UTF8,
4109                 0,                                      // dwFlags
4110                 wszURLPrev,
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
4116                 );
4117             if (cbWritten == 0)
4118                 continue;
4119
4120             DocNameOffsets docNameOffsets;
4121             BOOL fExists = m_pDocNameToOffsetMap->Lookup(szURL, &docNameOffsets);
4122             if (fExists)
4123             {
4124                 _ASSERTE(docNameOffsets.m_dwChksumTableOffset != (ULONG32) -1);
4125             }
4126             else
4127             {
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);
4135             }
4136
4137
4138             // * (4) CV_DebugSLinesFileBlockHeader_t
4139             if (pLineCur == NULL)
4140             {
4141                 // First lines file block, so begin the block header immediately after the
4142                 // subsection headers
4143                 pLinesFileBlockHeader = (CV_DebugSLinesFileBlockHeader_t *) pbLinesSubsectionCur;
4144             }
4145             else
4146             {
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;
4150             }
4151             
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));
4155
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
4160
4161             pLineCur = (CV_Line_t *) (pLinesFileBlockHeader + 1);
4162             pLineBlockStart = pLineCur;
4163             fBeginNewBlock = FALSE;
4164         }
4165
4166
4167         pLineCur->offset = m_rgIlNativeMap[iIlNativeMap].nativeOffset;
4168         pLineCur->linenumStart = 
4169             (iSeqPoints == kUnmappedIP) ? 
4170             kUnmappedIP : 
4171             m_rgnLineStarts[iSeqPoints];
4172         pLineCur->deltaLineEnd = 0;
4173         pLineCur->fStatement = 1;
4174                 ilOffsetPrev = (iSeqPoints == kUnmappedIP) ? kUnmappedIP : m_rgilOffsets[iSeqPoints];
4175                 pLinePrev = pLineCur;
4176         pLineCur++;
4177     }       // for (ULONG32 iMapIndexPairs=0; iMapIndexPairs < cMapIndexPairs; iMapIndexPairs++)
4178
4179     if (pLineCur == NULL)
4180     {
4181         // There were no lines data for this function, so don't write anything
4182         return S_OK;
4183     }
4184
4185     // Perform fixups against the last block we wrote
4186     if (FinalizeLinesFileBlock(pLinesFileBlockHeader, pLineBlockStart, pLineCur))
4187         fAtLeastOneBlockWritten = TRUE;
4188
4189     if (!fAtLeastOneBlockWritten)
4190     {
4191         // There were no valid blocks to write for this function, so don't bother
4192         // calling PDB writing API.  No problem.
4193         return S_OK;
4194     }
4195
4196     // Now that we know pSubSectHeader->cbLen, fill it in
4197     pSubSectHeader->cbLen = CV_off32_t(LPBYTE(pLineCur) - LPBYTE(pLinesHeader));
4198
4199     // Subsection is now filled out, so add it.
4200     hr = m_pWriter->ModAddSymbols(
4201         m_pMod,
4202         rgbLinesSubsection, 
4203
4204         // The size we pass here is the size of the entire byte array that we pass in.
4205         int(LPBYTE(pLineCur) - rgbLinesSubsection));
4206
4207     if (FAILED(hr))
4208         return hr;
4209
4210     return S_OK;
4211 }
4212
4213 //---------------------------------------------------------------------------------------
4214 //
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.
4219 //
4220 // Arguments:
4221 //      * ulCodeStartOffset - Offset relative to the code section, or where this region
4222 //          of code begins
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.
4226 //
4227
4228 HRESULT NGenMethodLinesPdbWriter::WriteDebugSILLinesSubsection(
4229     ULONG32 ulCodeStartOffset,
4230     ULONG32 cbCode,
4231     ICorDebugInfo::OffsetMapping * rgIlNativeMap,
4232     ULONG32 rgILNativeMapAdjustSize)
4233 {
4234     STANDARD_VM_CONTRACT;
4235
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:
4238     // 
4239     // * (1) DWORD = CV_SIGNATURE_C13 -- the usual subsection signature DWORD
4240     // * (2) CV_DebugSSubsectionHeader_t -- the usual subsection header, with type =
4241     //     DEBUG_S_LINES
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.
4252
4253     HRESULT hr;
4254
4255     CV_DebugSSubsectionHeader_t * pSubSectHeader = NULL;
4256     CV_DebugSLinesHeader_t * pLinesHeader = NULL;
4257     CV_DebugSLinesFileBlockHeader_t * pLinesFileBlockHeader = NULL;
4258
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(
4265         DEBUG_S_IL_LINES,
4266         ulCodeStartOffset,
4267         cbCode,
4268         rgILNativeMapAdjustSize,
4269         &pSubSectHeader,
4270         &pLinesHeader,
4271         &pbLinesSubsectionCur);
4272
4273     if (prgbLinesSubsection == NULL)
4274     {
4275         return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
4276     }
4277
4278     NewArrayHolder<BYTE> rgbLinesSubsection(prgbLinesSubsection);
4279
4280     // The loop below takes care of
4281     //     * (4) CV_DebugSLinesFileBlockHeader_t
4282     //     * (5) CV_Line_t (Line array entries)
4283     //
4284     CV_Line_t * pLineCur = NULL;
4285     CV_Line_t * pLineBlockStart = NULL;
4286     BOOL fBeginNewBlock = TRUE;
4287     LPBYTE pbEnd = NULL;
4288
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));
4293
4294     memset(pLinesFileBlockHeader, 0, sizeof(*pLinesFileBlockHeader));
4295     char szURL[MAX_PATH];
4296     int cbWritten = WideCharToMultiByte(
4297         CP_UTF8,
4298         0,                                      // dwFlags
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
4305         );
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
4312
4313     pLineCur = (CV_Line_t *)(pLinesFileBlockHeader + 1);
4314     pLineBlockStart = pLineCur;
4315     CV_Line_t * pLinePrev = NULL;
4316
4317     for (ULONG32 iINativeMap = 0;iINativeMap < rgILNativeMapAdjustSize; iINativeMap++)
4318     {
4319         if ((rgIlNativeMap[iINativeMap].ilOffset == NO_MAPPING) ||
4320             (rgIlNativeMap[iINativeMap].ilOffset == PROLOG) ||
4321             (rgIlNativeMap[iINativeMap].ilOffset == EPILOG))
4322         {
4323             rgIlNativeMap[iINativeMap].ilOffset = kUnmappedIP;
4324         }
4325
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)
4332         {
4333             if (pLinePrev->linenumStart == kUnmappedIP)
4334             {
4335                 // if the previous IL offset is kUnmappedIP, then we should rewrite it. 
4336                 pLineCur = pLinePrev;
4337             }
4338             else if (rgIlNativeMap[iINativeMap].ilOffset != kUnmappedIP &&
4339                 rgIlNativeMap[iINativeMap].ilOffset < pLinePrev->linenumStart)
4340             {
4341                 pLineCur = pLinePrev;
4342             }
4343             else
4344             {
4345                 // Found a native offset dupe, ignore the current map entry
4346                 continue;
4347             }
4348         }
4349
4350         pLineCur->linenumStart = rgIlNativeMap[iINativeMap].ilOffset;
4351
4352         pLineCur->offset = rgIlNativeMap[iINativeMap].nativeOffset;
4353         pLineCur->fStatement = 1;
4354         pLineCur->deltaLineEnd = 0;
4355         pLinePrev = pLineCur;
4356         pLineCur++;
4357     }
4358
4359     if (pLineCur == NULL)
4360     {
4361         // There were no lines data for this function, so don't write anything
4362         return S_OK;
4363     }
4364
4365     if (!FinalizeLinesFileBlock(pLinesFileBlockHeader, pLineBlockStart, pLineCur
4366 #ifdef _DEBUG
4367         , true
4368 #endif
4369         ))
4370     {
4371         return S_OK;
4372     }
4373
4374     // Now that we know pSubSectHeader->cbLen, fill it in
4375     pSubSectHeader->cbLen = CV_off32_t(LPBYTE(pLineCur) - LPBYTE(pLinesHeader));
4376
4377     // Subsection is now filled out, so add it.
4378     hr = m_pWriter->ModAddSymbols(
4379         m_pMod,
4380         rgbLinesSubsection,
4381
4382         // The size we pass here is the size of the entire byte array that we pass in.
4383         long(LPBYTE(pLineCur) - rgbLinesSubsection));
4384
4385     if (FAILED(hr))
4386         return hr;
4387
4388     return S_OK;
4389 }
4390
4391 //---------------------------------------------------------------------------------------
4392 //
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.
4396 //
4397 // Arguments:
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
4401 //
4402 // Return Value:
4403 //      * TRUE: lines-file block was nonempty, and is now finalized
4404 //      * FALSE: lines-file block was empty, and caller should toss it out.
4405 //
4406
4407 BOOL NGenMethodLinesPdbWriter::FinalizeLinesFileBlock(
4408     CV_DebugSLinesFileBlockHeader_t * pLinesFileBlockHeader, 
4409     CV_Line_t * pLineBlockStart,
4410     CV_Line_t * pLineBlockAfterEnd
4411 #ifdef _DEBUG
4412   , BOOL ignorekUnmappedIPCheck
4413 #endif
4414     )
4415 {
4416     LIMITED_METHOD_CONTRACT;
4417
4418     if (pLinesFileBlockHeader == NULL)
4419     {
4420         // If a given function has no sequence points at all, pLinesFileBlockHeader can
4421         // be NULL.  No problem
4422         return FALSE;
4423     }
4424
4425     if (pLineBlockStart == pLineBlockAfterEnd)
4426     {
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.
4430         return FALSE;
4431     }
4432
4433     _ASSERTE(pLineBlockStart != NULL);
4434     _ASSERTE(pLineBlockAfterEnd != NULL);
4435     _ASSERTE(pLineBlockAfterEnd > pLineBlockStart);
4436
4437     if (pLinesFileBlockHeader->offFile == (ULONG32) -1)
4438     {
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
4443         // reader.
4444 #ifdef _DEBUG
4445     {
4446         if (!ignorekUnmappedIPCheck)
4447         {
4448             for (CV_Line_t * pLineCur = pLineBlockStart; pLineCur < pLineBlockAfterEnd; pLineCur++)
4449             {
4450                 _ASSERTE(pLineCur->linenumStart == kUnmappedIP);
4451             }
4452         }
4453     }
4454 #endif // _DEBUG
4455         pLinesFileBlockHeader->offFile = 0;
4456     }
4457
4458     // Now that we know the size of the block, finish filling out the lines file block
4459     // header
4460     pLinesFileBlockHeader->nLines = CV_off32_t(pLineBlockAfterEnd - pLineBlockStart);
4461     pLinesFileBlockHeader->cbBlock = pLinesFileBlockHeader->nLines * sizeof(CV_Line_t);
4462     
4463     return TRUE;
4464 }
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)
4468 {
4469     STANDARD_VM_CONTRACT;
4470
4471     Assembly *pAssembly = reinterpret_cast<Assembly *>(hAssembly);
4472     _ASSERTE(pAssembly);
4473     _ASSERTE(pNativeImagePath);
4474     _ASSERTE(pPdbPath);
4475
4476 #if !defined(NO_NGENPDB)
4477     NGenPdbWriter pdbWriter(
4478         pNativeImagePath, 
4479         pPdbPath, 
4480         pdbLines ? kPDBLines : 0,
4481         pManagedPdbSearchPath);
4482     IfFailThrow(pdbWriter.Load(pDiasymreaderPath));
4483 #elif defined(FEATURE_PERFMAP)
4484     NativeImagePerfMap perfMap(pAssembly, pPdbPath);
4485 #endif
4486
4487     ModuleIterator moduleIterator = pAssembly->IterateModules();
4488     Module *pModule = NULL;
4489     BOOL fAtLeastOneNativeModuleFound = FALSE;
4490     
4491     while (moduleIterator.Next()) 
4492     {
4493         pModule = moduleIterator.GetModule();
4494
4495         if (pModule->HasNativeImage() || pModule->IsReadyToRun())
4496         {
4497 #if !defined(NO_NGENPDB)
4498             IfFailThrow(pdbWriter.WritePDBDataForModule(pModule));
4499 #elif defined(FEATURE_PERFMAP)
4500             perfMap.LogDataForModule(pModule);
4501 #endif
4502             fAtLeastOneNativeModuleFound = TRUE;
4503         }
4504     }
4505
4506     if (!fAtLeastOneNativeModuleFound)
4507     {
4508         GetSvcLogger()->Printf(
4509             W("Loaded image '%s' (for input file '%s') is not a native image.\n"),
4510             pAssembly->GetManifestFile()->GetPath().GetUnicode(),
4511             pNativeImagePath);
4512         return CORDBG_E_NO_IMAGE_AVAILABLE;
4513     }
4514
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"),
4520 #endif
4521         pNativeImagePath);
4522
4523     return S_OK;
4524 }
4525 #else
4526 HRESULT __stdcall CreatePdb(CORINFO_ASSEMBLY_HANDLE hAssembly, BSTR pNativeImagePath, BSTR pPdbPath, BOOL pdbLines, BSTR pManagedPdbSearchPath, LPCWSTR pDiasymreaderPath)
4527 {
4528     return E_NOTIMPL;
4529 }
4530 #endif // defined(FEATURE_PERFMAP) || !defined(NO_NGENPDB)
4531
4532 // End of PDB writing code
4533 // ----------------------------------------------------------------------------
4534
4535
4536 BOOL CEEPreloader::CanPrerestoreEmbedClassHandle(CORINFO_CLASS_HANDLE handle)
4537 {
4538     STANDARD_VM_CONTRACT;
4539
4540     if (IsReadyToRunCompilation())
4541         return FALSE;
4542
4543     TypeHandle th(handle);
4544
4545     return m_image->CanPrerestoreEagerBindToTypeHandle(th, NULL);
4546 }
4547
4548 BOOL CEEPreloader::CanPrerestoreEmbedMethodHandle(CORINFO_METHOD_HANDLE handle)
4549 {
4550     STANDARD_VM_CONTRACT;
4551
4552     if (IsReadyToRunCompilation())
4553         return FALSE;
4554
4555     MethodDesc *pMD = (MethodDesc*) handle;
4556
4557     return m_image->CanPrerestoreEagerBindToMethodDesc(pMD, NULL);
4558 }
4559
4560 ICorCompilePreloader * CEECompileInfo::PreloadModule(CORINFO_MODULE_HANDLE module,
4561                                                 ICorCompileDataStore *pData,
4562                                                 CorProfileData       *profileData)
4563 {
4564     STANDARD_VM_CONTRACT;
4565
4566     NewHolder<CEEPreloader> pPreloader(new CEEPreloader((Module *) module, pData));
4567     
4568     COOPERATIVE_TRANSITION_BEGIN();
4569
4570     if (PartialNGenStressPercentage() == 0)
4571     {
4572         pPreloader->Preload(profileData);
4573     }
4574
4575     COOPERATIVE_TRANSITION_END();
4576
4577     return pPreloader.Extract();
4578 }
4579
4580 void CEECompileInfo::SetAssemblyHardBindList(
4581     __in_ecount( cHardBindList )
4582         LPWSTR *pHardBindList,
4583     DWORD  cHardBindList)
4584 {
4585     STANDARD_VM_CONTRACT;
4586
4587 }
4588
4589 HRESULT CEECompileInfo::SetVerboseLevel(
4590          IN  VerboseLevel            level)
4591 {
4592     LIMITED_METHOD_CONTRACT;
4593     HRESULT hr = S_OK;
4594     g_CorCompileVerboseLevel = level;
4595     return hr;
4596 }
4597
4598 //
4599 // Preloader:
4600 //
4601 CEEPreloader::CEEPreloader(Module *pModule,
4602              ICorCompileDataStore *pData)
4603     : m_pData(pData)
4604 {
4605     m_image = new DataImage(pModule, this);
4606
4607     CONSISTENCY_CHECK(pModule == GetAppDomain()->ToCompilationDomain()->GetTargetModule());
4608
4609     GetAppDomain()->ToCompilationDomain()->SetTargetImage(m_image, this);
4610
4611     m_methodCompileLimit = pModule->GetMDImport()->GetCountWithTokenKind(mdtMethodDef) * 10;
4612
4613 #ifdef FEATURE_FULL_NGEN
4614     m_fSpeculativeTriage = FALSE;
4615     m_fDictionariesPopulated = FALSE;
4616 #endif
4617 }
4618
4619 CEEPreloader::~CEEPreloader()
4620 {
4621     WRAPPER_NO_CONTRACT;
4622     delete m_image;
4623 }
4624
4625 void CEEPreloader::Preload(CorProfileData * profileData)
4626 {
4627     STANDARD_VM_CONTRACT;
4628
4629     bool doNothingNgen = false;
4630 #ifdef _DEBUG
4631     static ConfigDWORD fDoNothingNGen;
4632     doNothingNgen = !!fDoNothingNGen.val(CLRConfig::INTERNAL_ZapDoNothing);
4633 #endif
4634
4635     if (!doNothingNgen)
4636     {
4637         m_image->GetModule()->SetProfileData(profileData);
4638         m_image->GetModule()->ExpandAll(m_image);
4639     }
4640
4641     // Triage all items created by initial expansion. 
4642     // We will try to accept all items created by initial expansion. 
4643     TriageForZap(TRUE);
4644 }
4645
4646 //
4647 // ICorCompilerPreloader
4648 //
4649
4650 DWORD CEEPreloader::MapMethodEntryPoint(CORINFO_METHOD_HANDLE handle)
4651 {
4652     STANDARD_VM_CONTRACT;
4653
4654     MethodDesc *pMD = GetMethod(handle);
4655     Precode * pPrecode = pMD->GetSavedPrecode(m_image);
4656
4657     return m_image->GetRVA(pPrecode);
4658 }
4659
4660 DWORD CEEPreloader::MapClassHandle(CORINFO_CLASS_HANDLE handle)
4661 {
4662     STANDARD_VM_CONTRACT;
4663
4664     TypeHandle th = TypeHandle::FromPtr(handle);
4665     if (th.IsTypeDesc())
4666         return m_image->GetRVA(th.AsTypeDesc()) | 2;
4667     else
4668         return m_image->GetRVA(th.AsMethodTable());
4669 }
4670
4671 DWORD CEEPreloader::MapMethodHandle(CORINFO_METHOD_HANDLE handle)
4672 {
4673     STANDARD_VM_CONTRACT;
4674
4675     return m_image->GetRVA(handle);
4676 }
4677
4678 DWORD CEEPreloader::MapFieldHandle(CORINFO_FIELD_HANDLE handle)
4679 {
4680     STANDARD_VM_CONTRACT;
4681
4682     return m_image->GetRVA(handle);
4683 }
4684
4685 DWORD CEEPreloader::MapAddressOfPInvokeFixup(CORINFO_METHOD_HANDLE handle)
4686 {
4687     STANDARD_VM_CONTRACT;
4688
4689     MethodDesc *pMD = GetMethod(handle);
4690
4691     _ASSERTE(pMD->IsNDirect());
4692     NDirectWriteableData * pMDWriteableData = ((NDirectMethodDesc *)pMD)->GetWriteableData();
4693
4694     return m_image->GetRVA(pMDWriteableData) + offsetof(NDirectWriteableData, m_pNDirectTarget);
4695 }
4696
4697 DWORD CEEPreloader::MapGenericHandle(CORINFO_GENERIC_HANDLE handle)
4698 {
4699     STANDARD_VM_CONTRACT;
4700
4701     return m_image->GetRVA(handle);
4702 }
4703
4704 DWORD CEEPreloader::MapModuleIDHandle(CORINFO_MODULE_HANDLE handle)
4705 {
4706     STANDARD_VM_CONTRACT;
4707
4708     return m_image->GetRVA(handle) + (DWORD)Module::GetOffsetOfModuleID();
4709 }
4710
4711 CORINFO_METHOD_HANDLE CEEPreloader::NextUncompiledMethod()
4712 {
4713     STANDARD_VM_CONTRACT;
4714
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)
4718     {
4719 #ifdef FEATURE_FULL_NGEN
4720         if (!m_fSpeculativeTriage)
4721         {
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;
4726         }
4727 #endif
4728
4729         if (m_uncompiledMethods.GetCount() == 0)
4730         {
4731 #ifdef FEATURE_FULL_NGEN
4732             if (!m_fDictionariesPopulated)
4733             {
4734                 // Prepopulate dictionaries. Only the first population is done in expansive way.
4735                 m_image->GetModule()->PrepopulateDictionaries(m_image, FALSE);
4736                 m_fDictionariesPopulated = TRUE;
4737             }
4738             else
4739 #endif
4740             {
4741                 // The subsequent populations are done in non-expansive way (won't load new types)
4742                 m_image->GetModule()->PrepopulateDictionaries(m_image, TRUE);
4743             }
4744             
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
4750             }
4751         }
4752     }
4753
4754     // Take next uncompiled method
4755     COUNT_T count = m_uncompiledMethods.GetCount();
4756     if (count == 0)
4757         return NULL;
4758
4759     MethodDesc * pMD = m_uncompiledMethods[count - 1];
4760     m_uncompiledMethods.SetCount(count - 1);
4761
4762 #ifdef _DEBUG 
4763     if (LoggingOn(LF_ZAP, LL_INFO10000))
4764     {
4765         StackSString methodString;
4766         TypeString::AppendMethodDebug(methodString, pMD);
4767
4768         LOG((LF_ZAP, LL_INFO10000, "CEEPreloader::NextUncompiledMethod: %S\n", methodString.GetUnicode()));
4769     }
4770 #endif // _DEBUG
4771
4772     return (CORINFO_METHOD_HANDLE) pMD;
4773 }
4774
4775 void CEEPreloader::AddMethodToTransitiveClosureOfInstantiations(CORINFO_METHOD_HANDLE handle)
4776 {
4777     STANDARD_VM_CONTRACT;
4778
4779     TriageMethodForZap(GetMethod(handle), TRUE);
4780 }
4781
4782 BOOL CEEPreloader::IsMethodInTransitiveClosureOfInstantiations(CORINFO_METHOD_HANDLE handle)
4783 {
4784     STANDARD_VM_CONTRACT;
4785
4786     MethodDesc *pMD = GetMethod(handle);
4787
4788     return (m_acceptedMethods.Lookup(pMD) != NULL) && (m_rejectedMethods.Lookup(pMD) == NULL);
4789 }
4790
4791 BOOL CEEPreloader::IsTypeInTransitiveClosureOfInstantiations(CORINFO_CLASS_HANDLE handle)
4792 {
4793     STANDARD_VM_CONTRACT;
4794
4795     TypeHandle th = (TypeHandle) handle;
4796
4797     return (m_acceptedTypes.Lookup(th) != NULL) && (m_rejectedTypes.Lookup(th) == NULL);
4798 }
4799
4800 void CEEPreloader::MethodReferencedByCompiledCode(CORINFO_METHOD_HANDLE handle)
4801 {
4802     STANDARD_VM_CONTRACT;
4803
4804 #ifndef FEATURE_FULL_NGEN // Unreferenced methods
4805     //
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.
4810     //
4811     MethodDesc *pMD = GetMethod(handle);
4812
4813     const CompileMethodEntry * pEntry = m_compileMethodsHash.LookupPtr(pMD);
4814     if (pEntry != NULL)
4815     {
4816         if (pEntry->fReferenced)
4817             return;
4818         const_cast<CompileMethodEntry *>(pEntry)->fReferenced = true;
4819
4820         if (pEntry->fScheduled)
4821             return;        
4822         AppendUncompiledMethod(pMD);
4823     }
4824     else
4825     {
4826         CompileMethodEntry entry;
4827         entry.pMD = pMD;
4828         entry.fReferenced = true;
4829         entry.fScheduled = false;
4830         m_compileMethodsHash.Add(entry);
4831     }
4832
4833     if (pMD->IsWrapperStub())
4834         MethodReferencedByCompiledCode((CORINFO_METHOD_HANDLE)pMD->GetWrappedMethodDesc());
4835 #endif // FEATURE_FULL_NGEN
4836 }
4837
4838 BOOL CEEPreloader::IsUncompiledMethod(CORINFO_METHOD_HANDLE handle)
4839 {
4840     STANDARD_VM_CONTRACT;
4841
4842     MethodDesc *pMD = GetMethod(handle);
4843
4844 #ifndef FEATURE_FULL_NGEN // Unreferenced methods
4845     const CompileMethodEntry * pEntry = m_compileMethodsHash.LookupPtr(pMD);
4846     return (pEntry != NULL) && (pEntry->fScheduled || !pEntry->fReferenced);
4847 #else
4848     return m_compileMethodsHash.LookupPtr(pMD) != NULL;
4849 #endif
4850 }
4851
4852 static bool IsTypeAccessibleOutsideItsAssembly(TypeHandle th)
4853 {
4854     STANDARD_VM_CONTRACT;
4855
4856     if (th.IsTypeDesc())
4857     {
4858         if (th.AsTypeDesc()->HasTypeParam())
4859             return IsTypeAccessibleOutsideItsAssembly(th.AsTypeDesc()->GetTypeParam());
4860
4861         return true;
4862     }
4863
4864     MethodTable * pMT = th.AsMethodTable();
4865
4866     if (pMT == g_pCanonMethodTableClass)
4867         return true;
4868
4869     switch (pMT->GetClass()->GetProtection())
4870     {
4871     case tdPublic:
4872         break;
4873     case tdNestedPublic:
4874     case tdNestedFamily:
4875     case tdNestedFamORAssem:
4876         {
4877             MethodTable * pMTEnclosing = pMT->LoadEnclosingMethodTable();
4878             if (pMTEnclosing == NULL)
4879                 return false;
4880             if (!IsTypeAccessibleOutsideItsAssembly(pMTEnclosing))
4881                 return false;
4882         }
4883         break;
4884
4885     default:
4886         return false;
4887     }
4888
4889     if (pMT->HasInstantiation())
4890     {
4891         Instantiation instantiation = pMT->GetInstantiation();
4892         for (DWORD i = 0; i < instantiation.GetNumArgs(); i++)
4893         {
4894             if (!IsTypeAccessibleOutsideItsAssembly(instantiation[i]))
4895                 return false;
4896         }
4897     }
4898
4899     return true;
4900 }
4901
4902 static bool IsMethodAccessibleOutsideItsAssembly(MethodDesc * pMD)
4903 {
4904     STANDARD_VM_CONTRACT;
4905
4906     // Note that this ignores friend access.
4907
4908     switch (pMD->GetAttrs() & mdMemberAccessMask)
4909     {
4910     case mdFamily:
4911     case mdFamORAssem:
4912     case mdPublic:
4913         break;
4914
4915     default:
4916         return false;
4917     }
4918
4919     if (!IsTypeAccessibleOutsideItsAssembly(pMD->GetMethodTable()))
4920         return false;
4921
4922     if (pMD->HasMethodInstantiation())
4923     {
4924         Instantiation instantiation = pMD->GetMethodInstantiation();
4925         for (DWORD i = 0; i < instantiation.GetNumArgs(); i++)
4926         {
4927             if (!IsTypeAccessibleOutsideItsAssembly(instantiation[i]))
4928                 return false;
4929         }
4930     }
4931
4932     return true;
4933 }
4934
4935 static bool IsMethodCallableOutsideItsAssembly(MethodDesc * pMD)
4936 {
4937     STANDARD_VM_CONTRACT;
4938
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())
4942         return true;
4943
4944     // Class constructors are often used with reflection. Always generate code for them.
4945     if (pMD->IsClassConstructorOrCtor())
4946         return true;
4947
4948     if (IsMethodAccessibleOutsideItsAssembly(pMD))
4949         return true;
4950
4951     return false;
4952 }
4953
4954 BOOL IsGenericTooDeeplyNested(TypeHandle t);
4955 void CEEPreloader::AddToUncompiledMethods(MethodDesc *pMD, BOOL fForStubs)
4956 {
4957     STANDARD_VM_CONTRACT;
4958
4959     // TriageTypeForZap() and TriageMethodForZap() should ensure this.
4960     _ASSERTE(m_image->GetModule() == pMD->GetLoaderModule());
4961
4962     if (!fForStubs)
4963     {
4964         if (!pMD->IsIL())
4965             return;
4966
4967         if (!pMD->MayHaveNativeCode() && !pMD->IsWrapperStub())
4968             return;
4969     }
4970
4971     // If it's already been compiled, don't add it to the set of uncompiled methods
4972     if (m_image->GetCodeAddress(pMD) != NULL)
4973         return;
4974     
4975     // If it's already in the queue to be compiled don't add it again
4976     const CompileMethodEntry * pEntry = m_compileMethodsHash.LookupPtr(pMD);
4977
4978 #ifndef FEATURE_FULL_NGEN // Unreferenced methods
4979    if (pEntry != NULL)
4980     {
4981         if (pEntry->fScheduled)
4982             return;
4983
4984         if (!pEntry->fReferenced)
4985             return;
4986
4987         const_cast<CompileMethodEntry *>(pEntry)->fScheduled = true;
4988     }
4989     else
4990     {
4991         // The unreferenced methods optimization works for generic methods and methods on generic types only. 
4992         // Non-generic methods take different path.
4993         //
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.
4997
4998         bool fSchedule = fForStubs || IsMethodCallableOutsideItsAssembly(pMD);
4999
5000         CompileMethodEntry entry;
5001         entry.pMD = pMD;
5002         entry.fScheduled = fSchedule;
5003         entry.fReferenced = false;
5004         m_compileMethodsHash.Add(entry);
5005
5006         if (!fSchedule)
5007             return;
5008     }
5009 #else // // FEATURE_FULL_NGEN
5010     // Schedule the method for compilation
5011     if (pEntry != NULL)
5012         return;
5013     CompileMethodEntry entry;
5014     entry.pMD = pMD;
5015     m_compileMethodsHash.Add(entry);
5016 #endif // FEATURE_FULL_NGEN
5017
5018     if (pMD->HasMethodInstantiation())
5019     {
5020         Instantiation instantiation = pMD->GetMethodInstantiation();
5021         for (DWORD i = 0; i < instantiation.GetNumArgs(); i++)
5022         {
5023             if (IsGenericTooDeeplyNested(instantiation[i]))
5024                 return;
5025         }
5026     }
5027
5028     // Add it to the set of uncompiled methods
5029     AppendUncompiledMethod(pMD);
5030 }
5031
5032 //
5033 // Used to validate instantiations produced by the production rules before we actually try to instantiate them.
5034 //
5035 static BOOL CanSatisfyConstraints(Instantiation typicalInst, Instantiation candidateInst)
5036 {
5037     STANDARD_VM_CONTRACT;
5038
5039     // The dependency must be of the form C<T> --> D<T>
5040     _ASSERTE(typicalInst.GetNumArgs() == candidateInst.GetNumArgs());
5041     if (typicalInst.GetNumArgs() != candidateInst.GetNumArgs())
5042         return FALSE;
5043
5044     SigTypeContext typeContext(candidateInst, Instantiation());
5045
5046     for (DWORD i = 0; i < candidateInst.GetNumArgs(); i++)
5047     {
5048         TypeHandle thArg = candidateInst[i];
5049
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))
5053             continue;
5054
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.
5059         //
5060         // For example of where this does not hold, consider if
5061         //     class C<T>
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>
5069
5070         TypeVarTypeDesc* tyvar = typicalInst[i].AsGenericVariable();
5071
5072         tyvar->LoadConstraints();
5073
5074         if (!tyvar->SatisfiesConstraints(&typeContext,thArg)) {
5075 #ifdef _DEBUG
5076             /*
5077             // In case we want to know which illegal instantiations we ngen'ed
5078             StackSString candidateInstName;
5079             StackScratchBuffer buffer;
5080             thArg.GetName(candidateInstName);
5081             char output[1024];
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);
5084             */
5085 #endif
5086             return FALSE;
5087         }
5088     }
5089
5090     return TRUE;
5091 }
5092
5093
5094 //
5095 // This method has duplicated logic from bcl\system\collections\generic\comparer.cs
5096 //
5097 static void SpecializeComparer(SString& ss, Instantiation& inst)
5098 {
5099     STANDARD_VM_CONTRACT;
5100
5101     if (inst.GetNumArgs() != 1) {
5102         _ASSERTE(!"Improper use of a TypeDependencyAttribute for Comparer");
5103         return;
5104     }
5105
5106     TypeHandle elemTypeHnd = inst[0];
5107
5108     //
5109     // Override the default ObjectComparer for special cases
5110     //
5111     if (elemTypeHnd.CanCastTo(
5112         TypeHandle(MscorlibBinder::GetClass(CLASS__ICOMPARABLEGENERIC)).Instantiate(Instantiation(&elemTypeHnd, 1))))
5113     {
5114         ss.Set(W("System.Collections.Generic.GenericComparer`1"));
5115         return;
5116     }
5117
5118     if (Nullable::IsNullableType(elemTypeHnd))
5119     {
5120         Instantiation nullableInst = elemTypeHnd.AsMethodTable()->GetInstantiation();
5121         if (nullableInst[0].CanCastTo(
5122             TypeHandle(MscorlibBinder::GetClass(CLASS__ICOMPARABLEGENERIC)).Instantiate(nullableInst)))
5123         {
5124             ss.Set(W("System.Collections.Generic.NullableComparer`1"));
5125             inst = nullableInst;
5126             return;
5127         }
5128     }
5129
5130     if (elemTypeHnd.IsEnum())
5131     {
5132         CorElementType et = elemTypeHnd.GetVerifierCorElementType();
5133         if (et == ELEMENT_TYPE_I1 ||
5134             et == ELEMENT_TYPE_I2 ||
5135             et == ELEMENT_TYPE_I4)
5136         {
5137             ss.Set(W("System.Collections.Generic.Int32EnumComparer`1"));
5138             return;
5139         }
5140         if (et == ELEMENT_TYPE_U1 ||
5141             et == ELEMENT_TYPE_U2 ||
5142             et == ELEMENT_TYPE_U4)
5143         {
5144             ss.Set(W("System.Collections.Generic.UInt32EnumComparer`1"));
5145             return;
5146         }
5147         if (et == ELEMENT_TYPE_I8)
5148         {
5149             ss.Set(W("System.Collections.Generic.Int64EnumComparer`1"));
5150             return;
5151         }
5152         if (et == ELEMENT_TYPE_U8)
5153         {
5154             ss.Set(W("System.Collections.Generic.UInt64EnumComparer`1"));
5155             return;
5156         }
5157     }
5158 }
5159
5160 //
5161 // This method has duplicated logic from bcl\system\collections\generic\equalitycomparer.cs
5162 // and matching logic in jitinterface.cpp
5163 //
5164 static void SpecializeEqualityComparer(SString& ss, Instantiation& inst)
5165 {
5166     STANDARD_VM_CONTRACT;
5167
5168     if (inst.GetNumArgs() != 1) {
5169         _ASSERTE(!"Improper use of a TypeDependencyAttribute for EqualityComparer");
5170         return;
5171     }
5172
5173     TypeHandle elemTypeHnd = inst[0];
5174
5175     //
5176     // Override the default ObjectEqualityComparer for special cases
5177     //
5178     if (elemTypeHnd.CanCastTo(
5179         TypeHandle(MscorlibBinder::GetClass(CLASS__IEQUATABLEGENERIC)).Instantiate(Instantiation(&elemTypeHnd, 1))))
5180     {
5181         ss.Set(W("System.Collections.Generic.GenericEqualityComparer`1"));
5182         return;
5183     }
5184
5185     if (Nullable::IsNullableType(elemTypeHnd))
5186     {
5187         Instantiation nullableInst = elemTypeHnd.AsMethodTable()->GetInstantiation();
5188         if (nullableInst[0].CanCastTo(
5189             TypeHandle(MscorlibBinder::GetClass(CLASS__IEQUATABLEGENERIC)).Instantiate(nullableInst)))
5190         {
5191             ss.Set(W("System.Collections.Generic.NullableEqualityComparer`1"));
5192             inst = nullableInst;
5193             return;
5194         }
5195     }
5196
5197     if (elemTypeHnd.IsEnum())
5198     {
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)
5208         {
5209             ss.Set(W("System.Collections.Generic.EnumEqualityComparer`1"));
5210             return;
5211         }
5212         else if (et == ELEMENT_TYPE_I8 ||
5213                  et == ELEMENT_TYPE_U8)
5214         {
5215             ss.Set(W("System.Collections.Generic.LongEnumEqualityComparer`1"));
5216             return;
5217         }
5218     }
5219 }
5220
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)
5225 {
5226     STANDARD_VM_CONTRACT;
5227
5228     Instantiation inst = pMT->GetInstantiation();
5229     for (DWORD i = 0; i < inst.GetNumArgs(); i++)
5230     {
5231         TypeHandle th = inst[i];
5232         if (th.IsProjectedFromWinRT() && !th.GetModule()->IsWindowsRuntimeModule())
5233             return TRUE;
5234     }
5235     return FALSE;
5236 }
5237 #endif
5238
5239 void CEEPreloader::ApplyTypeDependencyProductionsForType(TypeHandle t)
5240 {
5241     STANDARD_VM_CONTRACT;
5242
5243     // Only actual types
5244     if (t.IsTypeDesc())
5245         return;
5246
5247     MethodTable * pMT = t.AsMethodTable();
5248
5249     if (!pMT->HasInstantiation() || pMT->ContainsGenericVariables())
5250         return;
5251
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))
5256     {
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())
5260         {
5261             TypeHandle thWinRT;
5262             WinMDAdapter::RedirectedTypeIndex index;
5263             if (WinRTInterfaceRedirector::ResolveRedirectedInterface(pMT, &index))
5264             {
5265                 // redirected interface needs the mscorlib-local definition of the corresponding WinRT type
5266                 MethodTable *pWinRTMT = WinRTInterfaceRedirector::GetWinRTTypeForRedirectedInterfaceIndex(index);
5267                 thWinRT = TypeHandle(pWinRTMT);
5268
5269                 // and matching stub methods
5270                 WORD wNumSlots = pWinRTMT->GetNumVirtuals();
5271                 for (WORD i = 0; i < wNumSlots; i++)
5272                 {
5273                     MethodDesc *pAdapterMD = WinRTInterfaceRedirector::GetStubMethodForRedirectedInterface(
5274                         index,
5275                         i,
5276                         TypeHandle::Interop_NativeToManaged,
5277                         FALSE,
5278                         pMT->GetInstantiation());
5279
5280                     TriageMethodForZap(pAdapterMD, TRUE);
5281                 }
5282             }
5283             if (WinRTDelegateRedirector::ResolveRedirectedDelegate(pMT, &index))
5284             {
5285                 // redirected delegate needs the mscorlib-local definition of the corresponding WinRT type
5286                 thWinRT = TypeHandle(WinRTDelegateRedirector::GetWinRTTypeForRedirectedDelegateIndex(index));
5287             }
5288
5289             if (!thWinRT.IsNull())
5290             {
5291                 thWinRT = thWinRT.Instantiate(pMT->GetInstantiation());
5292                 TriageTypeForZap(thWinRT, TRUE);
5293             }
5294         }
5295     }
5296 #endif // FEATURE_COMINTEROP
5297
5298     pMT = pMT->GetCanonicalMethodTable();
5299
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()) {
5303         return;
5304     }
5305
5306     // Part 1. - check for an NGEN production rule specified by a use of CompilerServices.TypeDependencyAttribute
5307     //  e.g. C<T> --> D<T>
5308     //
5309     // For example, if C<int> is generated then we produce D<int>.
5310     //
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.
5319     //
5320     IMDInternalImport *pImport = pMT->GetMDImport();
5321     HRESULT hr;
5322
5323     _ASSERTE(pImport);
5324     //walk all of the TypeDependencyAttributes
5325     MDEnumHolder hEnum(pImport);
5326     hr = pImport->EnumCustomAttributeByNameInit(pMT->GetCl(),
5327                                                 g_CompilerServicesTypeDependencyAttribute, &hEnum);
5328     if (SUCCEEDED(hr))
5329     {
5330         mdCustomAttribute tkAttribute;
5331         const BYTE *pbAttr;
5332         ULONG cbAttr;
5333
5334         while (pImport->EnumNext(&hEnum, &tkAttribute))
5335         {
5336             //get attribute and validate format
5337             if (FAILED(pImport->GetCustomAttributeAsBlob(
5338                 tkAttribute,
5339                 reinterpret_cast<const void **>(&pbAttr),
5340                 &cbAttr)))
5341             {
5342                 continue;
5343             }
5344
5345             CustomAttributeParser cap(pbAttr, cbAttr);
5346             if (FAILED(cap.SkipProlog()))
5347                 continue;
5348
5349             LPCUTF8 szString;
5350             ULONG   cbString;
5351             if (FAILED(cap.GetNonNullString(&szString, &cbString)))
5352                 continue;
5353
5354             StackSString ss(SString::Utf8, szString, cbString);
5355             Instantiation inst = pMT->GetInstantiation();
5356
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))
5361                 continue;
5362 #endif
5363
5364             if (ss.Equals(W("System.Collections.Generic.ObjectComparer`1")))
5365             {
5366                 SpecializeComparer(ss, inst);
5367             }
5368             else
5369             if (ss.Equals(W("System.Collections.Generic.ObjectEqualityComparer`1")))
5370             {
5371                 SpecializeEqualityComparer(ss, inst);
5372             }
5373
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());
5377
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())
5382                 continue;
5383
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))
5388             {
5389 #ifdef FEATURE_FULL_NGEN
5390                 if (pMT->GetNumGenericArgs() != 1 || !pMT->IsInterface()) {
5391                     _ASSERTE(!"Improper use of a TypeDependencyAttribute for SZArrayHelper");
5392                     continue;
5393                 }
5394                 TypeHandle elemTypeHnd = pMT->GetInstantiation()[0];
5395                 if (elemTypeHnd.IsValueType())
5396                     ApplyTypeDependencyForSZArrayHelper(pMT, elemTypeHnd);
5397 #endif
5398                 continue;
5399             }
5400
5401             _ASSERTE(typicalDepTH.IsTypicalTypeDefinition());
5402             if (!typicalDepTH.IsTypicalTypeDefinition())
5403                 continue;
5404
5405             // It certainly can't be immediately recursive...
5406             _ASSERTE(!typicalDepTH.GetMethodTable()->HasSameTypeDefAs(pMT));
5407
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,
5411
5412             if (CanSatisfyConstraints(typicalDepTH.GetInstantiation(), inst))
5413             {
5414                 TypeHandle instDepTH =
5415                     ClassLoader::LoadGenericInstantiationThrowing(typicalDepTH.GetModule(), typicalDepTH.GetCl(), inst);
5416
5417                 _ASSERTE(!instDepTH.ContainsGenericVariables());
5418                 _ASSERTE(instDepTH.GetNumGenericArgs() == typicalDepTH.GetNumGenericArgs());
5419                 _ASSERTE(instDepTH.GetMethodTable()->HasSameTypeDefAs(typicalDepTH.GetMethodTable()));
5420
5421                 // OK, add the generated type to the dependency set
5422                 TriageTypeForZap(instDepTH, TRUE);
5423             }
5424         }
5425     }
5426 } // CEEPreloader::ApplyTypeDependencyProductionsForType
5427
5428
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)
5436 {
5437     STANDARD_VM_CONTRACT;
5438
5439     _ASSERTE(elemTypeHnd.AsMethodTable()->IsValueType());
5440
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);
5444
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 };
5456
5457     static const int cReadOnlyMethods = 3;
5458     static const int cAllMethods = 7;
5459
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>
5464     };
5465     
5466     // Assuming the binder ID's are properly laid out in mscorlib.h
5467 #if _DEBUG
5468     for(unsigned int i=0; i < NumItems(LastMethodOnGenericArrayInterfaces) - 1; i++) {
5469         _ASSERTE(LastMethodOnGenericArrayInterfaces[i] < LastMethodOnGenericArrayInterfaces[i+1]);
5470     }
5471 #endif
5472
5473     MethodTable* pExactMT = MscorlibBinder::GetClass(CLASS__SZARRAYHELPER);
5474
5475     // Subtract one from the non-generic IEnumerable that the generic IEnumerable<T>
5476     // inherits from.  
5477     unsigned inheritanceDepth = pInterfaceMT->GetNumInterfaces() - 1;
5478     PREFIX_ASSUME(0 <= inheritanceDepth && inheritanceDepth < NumItems(LastMethodOnGenericArrayInterfaces));
5479     
5480     // Read-only interfaces happen to always have one method
5481     bool fIsReadOnly = pInterfaceMT->GetNumVirtuals() == 1;
5482
5483     for(int i=0; i < (fIsReadOnly ? cReadOnlyMethods : cAllMethods); i++)
5484     {
5485         // Check whether the method applies for this type.
5486         if (SZArrayHelperMethodIDs[i] > LastMethodOnGenericArrayInterfaces[inheritanceDepth])
5487             continue;
5488
5489         MethodDesc * pPrimaryMD = MscorlibBinder::GetMethod(SZArrayHelperMethodIDs[i]);
5490
5491         MethodDesc * pInstantiatedMD = MethodDesc::FindOrCreateAssociatedMethodDesc(pPrimaryMD, 
5492                                            pExactMT, false, Instantiation(&elemTypeHnd, 1), false);
5493
5494         TriageMethodForZap(pInstantiatedMD, true);
5495     }
5496 }
5497
5498
5499 void CEEPreloader::AddTypeToTransitiveClosureOfInstantiations(CORINFO_CLASS_HANDLE handle)
5500 {
5501     STANDARD_VM_CONTRACT;
5502
5503     TriageTypeForZap((TypeHandle) handle, TRUE);
5504 }
5505
5506 const unsigned MAX_ZAP_INSTANTIATION_NESTING = 10;
5507
5508 BOOL IsGenericTooDeeplyNested(TypeHandle t)
5509 {
5510     CONTRACTL
5511     {
5512         NOTHROW;
5513         MODE_ANY;
5514     }
5515     CONTRACTL_END;
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.
5518
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];
5523
5524     //the ordinal in the GetInstantiation for the current type (over [0,
5525     //GetNumGenericArg())
5526     unsigned currentGenericArgEdge[MAX_ZAP_INSTANTIATION_NESTING];
5527
5528     //initialize the DFS.
5529     memset(currentGenericArgEdge, 0, sizeof(currentGenericArgEdge));
5530     currentVisitingType[0] = t;
5531     currentQueueIdx = 0;
5532
5533     while( currentQueueIdx >= 0 )
5534     {
5535         //see if we're done with this node
5536         if( currentVisitingType[currentQueueIdx].GetNumGenericArgs()
5537             <= currentGenericArgEdge[currentQueueIdx] )
5538         {
5539             --currentQueueIdx;
5540         }
5541         else
5542         {
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()  )
5550             {
5551                 //new edge.  Make sure there is space in the queue.
5552                 if( (currentQueueIdx + 1) >= (int)NumItems(currentGenericArgEdge) )
5553                 {
5554                     //exceeded the allowable depth.  Stop processing.
5555                     return TRUE;
5556                 }
5557                 else
5558                 {
5559                     ++currentQueueIdx;
5560                     currentGenericArgEdge[currentQueueIdx] = 0;
5561                     currentVisitingType[currentQueueIdx] = current;
5562                 }
5563             }
5564         }
5565     }
5566
5567     return FALSE;
5568 }
5569
5570 void CEEPreloader::TriageTypeForZap(TypeHandle th, BOOL fAcceptIfNotSure, BOOL fExpandDependencies)
5571 {
5572     STANDARD_VM_CONTRACT;
5573
5574     // We care about param types only
5575     if (th.IsTypicalTypeDefinition() && !th.IsTypeDesc())
5576         return;
5577
5578     // We care about types from our module only
5579     if (m_image->GetModule() != th.GetLoaderModule())
5580         return;
5581
5582     // Check if we have decided to accept this type already.
5583     if (m_acceptedTypes.Lookup(th) != NULL)
5584         return;
5585
5586     // Check if we have decided to reject this type already.
5587     if (m_rejectedTypes.Lookup(th) != NULL)
5588         return;
5589
5590     enum { Investigate, Accepted, Rejected } triage = Investigate;
5591
5592     const char * rejectReason = NULL;
5593
5594     // TypeVarTypeDesc are saved via links from code:Module::m_GenericParamToDescMap
5595     if (th.IsGenericVariable())
5596     {
5597         triage = Rejected;
5598         rejectReason = "type is a Generic variable";
5599         goto Done;
5600     }
5601
5602     /* Consider this example:
5603
5604     class A<T> {}
5605     class B<U> : A<U> {}
5606
5607     class C<V> : B<V> 
5608     {
5609         void foo<W>()
5610         {
5611             typeof(C<W>);
5612             typeof(B<A<W>>);
5613
5614             typeof(List<V>);
5615         }
5616     }
5617
5618     The open instantiations can be divided into the following 3 categories:
5619
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>().
5628
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.
5633     */
5634     if (th.ContainsGenericVariables(TRUE/*methodTypeVarsOnly*/))
5635     {
5636         triage = Rejected;
5637         rejectReason = "type contains method generic variables";
5638         goto Done;
5639     }
5640
5641     // Filter out weird cases we do not care about.
5642     if (!m_image->GetModule()->GetAvailableParamTypes()->ContainsValue(th))
5643     {
5644         triage = Rejected;
5645         rejectReason = "type is not in the current module";
5646         return;
5647     }
5648
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())
5652     {
5653         // This may load new types. May load new types.
5654         ClassLoader::TryEnsureLoaded(th);
5655
5656         if (!th.IsFullyLoaded())
5657         {
5658             triage = Rejected;
5659             rejectReason = "type could not be fully loaded, possibly because it does not satisfy its constraints";
5660             goto Done;
5661         }
5662     }
5663
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())
5668     {
5669         triage = Rejected;
5670         rejectReason = "type contains generic variables from another module";
5671         goto Done;
5672     }
5673
5674     // Always store items in their preferred zap module even if we are not sure
5675     if (Module::GetPreferredZapModuleForTypeHandle(th) == m_image->GetModule())
5676     {
5677         triage = Accepted;
5678         goto Done;
5679     }
5680
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())
5685     {
5686         triage = Rejected;
5687         rejectReason = "type is a TypeDesc";
5688         goto Done;
5689     }
5690
5691     {
5692         // Do not save instantiations found in one of our hardbound dependencies
5693         PtrHashMap::PtrIterator iter = GetAppDomain()->ToCompilationDomain()->IterateHardBoundModules();
5694         for (/**/; !iter.end(); ++iter)
5695         {
5696             Module * hardBoundModule = (Module*)iter.GetValue();
5697             if (hardBoundModule->GetAvailableParamTypes()->ContainsValue(th))
5698             {
5699                 triage = Rejected;
5700                 rejectReason = "type was found in a hardbound dependency";
5701                 goto Done;
5702             }
5703         }
5704     }
5705
5706     // We are not really sure about this type. Accept it only if we have been asked to.
5707     if (fAcceptIfNotSure)
5708     {
5709         if (!m_fSpeculativeTriage)
5710         {
5711             // We will take a look later before we actually start compiling the instantiations
5712             m_speculativeTypes.Append(th);
5713             m_acceptedTypes.Add(th);
5714             return;
5715         }
5716
5717         triage = Accepted;
5718         goto Done;
5719     }
5720 #else
5721     rejectReason = "type is not in the preferred module";
5722     triage = Rejected;
5723 #endif
5724
5725 Done:
5726     switch (triage)
5727     {
5728     case Accepted:
5729         m_acceptedTypes.Add(th);
5730         if (fExpandDependencies)
5731         {
5732             ExpandTypeDependencies(th);
5733         }
5734         break;
5735
5736     case Rejected:
5737
5738         m_rejectedTypes.Add(th);
5739
5740 #ifdef LOGGING
5741         // It is expensive to call th.GetName, only do it when we are actually logging
5742         if (LoggingEnabled())
5743         {
5744             SString typeName;
5745             th.GetName(typeName);
5746             LOG((LF_ZAP, LL_INFO10000, "TriageTypeForZap rejects %S (%08x) because %s\n", 
5747                  typeName.GetUnicode(), th.AsPtr(), rejectReason));
5748         }
5749 #endif
5750         break;
5751
5752     default:
5753         // We have not found a compeling reason to accept or reject the type yet. Maybe next time...
5754         break;
5755     }
5756 }
5757
5758 void CEEPreloader::ExpandTypeDependencies(TypeHandle th)
5759 {
5760     STANDARD_VM_CONTRACT;
5761
5762     if (th.IsTypeDesc())
5763         return;
5764     
5765     MethodTable* pMT = th.AsMethodTable();
5766
5767     if (pMT->IsCanonicalMethodTable())
5768     {
5769         // Cutoff infinite recursion.
5770         if (!IsGenericTooDeeplyNested(th))
5771         {
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())
5778             {
5779                 AddToUncompiledMethods(itr.GetMethodDesc(), FALSE);
5780             }
5781         }
5782     }
5783     else
5784     {
5785         // Make sure canonical method table is saved
5786         TriageTypeForZap(pMT->GetCanonicalMethodTable(), TRUE);
5787     }
5788     
5789     if (pMT->SupportsGenericInterop(TypeHandle::Interop_ManagedToNative))
5790     {
5791         MethodTable::IntroducedMethodIterator itr(pMT->GetCanonicalMethodTable());
5792         for (/**/; itr.IsValid(); itr.Next())
5793         {
5794             MethodDesc *pMD = itr.GetMethodDesc();
5795
5796             if (!pMD->HasMethodInstantiation())
5797             {
5798                 if (pMT->IsInterface() || !pMD->IsSharedByGenericInstantiations())
5799                 {
5800                     pMD = MethodDesc::FindOrCreateAssociatedMethodDesc(
5801                         pMD, 
5802                         pMT, 
5803                         FALSE,              // forceBoxedEntryPoint
5804                         Instantiation(),    // methodInst
5805                         FALSE,              // allowInstParam
5806                         TRUE);              // forceRemotableMethod
5807                 }
5808                 else
5809                 {
5810                     _ASSERTE(pMT->IsDelegate());
5811                     pMD = InstantiatedMethodDesc::FindOrCreateExactClassMethod(pMT, pMD);
5812                 }
5813
5814                 AddToUncompiledMethods(pMD, TRUE);
5815             }
5816         }
5817     }
5818
5819     // Make sure parent type is saved
5820     TriageTypeForZap(pMT->GetParentMethodTable(), TRUE);
5821     
5822     // Make sure all instantiation arguments are saved
5823     Instantiation inst = pMT->GetInstantiation();
5824     for (DWORD iArg = 0; iArg < inst.GetNumArgs(); iArg++)
5825     {
5826         TriageTypeForZap(inst[iArg], TRUE);
5827     }
5828     
5829     // Make sure all interfaces implemeted by the class are saved
5830     MethodTable::InterfaceMapIterator intIterator = pMT->IterateInterfaceMap();
5831     while (intIterator.Next())
5832     {
5833         TriageTypeForZap(intIterator.GetInterface(), TRUE);
5834     }
5835     
5836     // Make sure aprox types for all fields are saved
5837     ApproxFieldDescIterator fdIterator(pMT, ApproxFieldDescIterator::ALL_FIELDS);
5838     FieldDesc* pFD;
5839     while ((pFD = fdIterator.Next()) != NULL)
5840     {
5841         if (pFD->GetFieldType() == ELEMENT_TYPE_VALUETYPE)
5842         {
5843             TriageTypeForZap(pFD->GetFieldTypeHandleThrowing(), TRUE);
5844         }
5845     }
5846     
5847     // Make sure types for all generic static fields are saved
5848     
5849     if (pMT->HasGenericsStaticsInfo())
5850     {
5851         FieldDesc *pGenStaticFields = pMT->GetGenericsStaticFieldDescs();
5852         DWORD nFields = pMT->GetNumStaticFields();
5853         for (DWORD iField = 0; iField < nFields; iField++)
5854         {
5855             FieldDesc* pField = &pGenStaticFields[iField];
5856             if (pField->GetFieldType() == ELEMENT_TYPE_VALUETYPE)
5857             {
5858                 TriageTypeForZap(pField->GetFieldTypeHandleThrowing(), TRUE);
5859             }
5860         }
5861     }
5862     
5863     // Expand type using the custom rules. May load new types.
5864     ApplyTypeDependencyProductionsForType(th);
5865 }
5866
5867 // Triage instantiations of generic methods
5868
5869 void CEEPreloader::TriageMethodForZap(MethodDesc* pMD, BOOL fAcceptIfNotSure, BOOL fExpandDependencies)
5870 {
5871     STANDARD_VM_CONTRACT;
5872
5873     // Submit the method type for triage
5874     TriageTypeForZap(TypeHandle(pMD->GetMethodTable()), fAcceptIfNotSure);
5875
5876     // We care about instantiated methods only
5877     if (pMD->IsTypicalMethodDefinition())
5878         return;
5879
5880     // We care about methods from our module only
5881     if (m_image->GetModule() != pMD->GetLoaderModule())
5882         return;
5883
5884     // Check if we have decided to accept this method already.
5885     if (m_acceptedMethods.Lookup(pMD) != NULL)
5886         return;
5887
5888     // Check if we have decided to reject this method already.
5889     if (m_rejectedMethods.Lookup(pMD) != NULL)
5890         return;
5891
5892     enum { Investigate, Accepted, Rejected } triage = Investigate;
5893
5894     const char * rejectReason = NULL;
5895
5896     // Do not save open methods
5897     if (pMD->ContainsGenericVariables())
5898     {
5899         triage = Rejected;
5900         rejectReason = "method contains method generic variables";
5901         goto Done;
5902     }
5903
5904     // Always store items in their preferred zap module even if we are not sure
5905     if (Module::GetPreferredZapModuleForMethodDesc(pMD) == m_image->GetModule())
5906     {
5907         triage = Accepted;
5908         goto Done;
5909     }
5910
5911 #ifdef FEATURE_FULL_NGEN
5912     {
5913         // Do not save instantiations found in one of our hardbound dependencies
5914         PtrHashMap::PtrIterator iter = GetAppDomain()->ToCompilationDomain()->IterateHardBoundModules();
5915         for (/**/; !iter.end(); ++iter)
5916         {
5917             Module * hardBoundModule = (Module*)iter.GetValue();
5918             if (hardBoundModule->GetInstMethodHashTable()->ContainsMethodDesc(pMD))
5919             {
5920                 triage = Rejected;
5921                 rejectReason = "method was found in a hardbound dependency";
5922                 goto Done;
5923             }
5924         }
5925     }
5926
5927     // We are not really sure about this method. Accept it only if we have been asked to.
5928     if (fAcceptIfNotSure)
5929     {
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)
5933         // {
5934         //    // We will take a look later before we actually start compiling the instantiations
5935         //    ...
5936         // }
5937
5938         triage = Accepted;
5939         goto Done;
5940     }
5941 #else
5942     triage = Rejected;
5943 #endif
5944
5945 Done:
5946     switch (triage)
5947     {
5948     case Accepted:
5949         m_acceptedMethods.Add(pMD);
5950         if (fExpandDependencies)
5951         {
5952             ExpandMethodDependencies(pMD);
5953         }
5954         break;
5955
5956     case Rejected:
5957         m_rejectedMethods.Add(pMD);
5958         LOG((LF_ZAP, LL_INFO10000, "TriageMethodForZap rejects %s (%08x) because %s\n", 
5959             pMD->m_pszDebugMethodName, pMD, rejectReason));
5960         break;
5961
5962     default:
5963         // We have not found a compeling reason to accept or reject the method yet. Maybe next time...
5964         break;
5965     }
5966 }
5967
5968 void CEEPreloader::ExpandMethodDependencies(MethodDesc * pMD)
5969 {
5970     STANDARD_VM_CONTRACT;
5971
5972     AddToUncompiledMethods(pMD, FALSE);
5973
5974     {
5975         // Make sure all instantiation arguments are saved
5976         Instantiation inst = pMD->GetMethodInstantiation();
5977         for (DWORD iArg = 0; iArg < inst.GetNumArgs(); iArg++)
5978         {
5979             TriageTypeForZap(inst[iArg], TRUE);
5980         }
5981     }
5982
5983     // Make sure to add wrapped method desc
5984     if (pMD->IsWrapperStub())
5985         TriageMethodForZap(pMD->GetWrappedMethodDesc(), TRUE);
5986 }
5987
5988 void CEEPreloader::TriageTypeFromSoftBoundModule(TypeHandle th, Module * pSoftBoundModule)
5989 {
5990     STANDARD_VM_CONTRACT;
5991
5992     // We care about types from our module only
5993     if (m_image->GetModule() != th.GetLoaderModule())
5994         return;
5995
5996     // Nothing to do if we have rejected the type already.
5997     if (m_rejectedTypes.Lookup(th) != NULL)
5998         return;
5999
6000     // We make guarantees about types living in its own PZM only
6001     if (Module::GetPreferredZapModuleForTypeHandle(th) != pSoftBoundModule)
6002         return;
6003
6004     // Reject the type - it is guaranteed to be saved in PZM
6005     m_rejectedTypes.Add(th);
6006
6007     if (!th.IsTypeDesc())
6008     {
6009         // Reject the canonical method table if possible.
6010         MethodTable* pMT = th.AsMethodTable();
6011         if (!pMT->IsCanonicalMethodTable())
6012             TriageTypeFromSoftBoundModule(pMT->GetCanonicalMethodTable(), pSoftBoundModule);
6013
6014         // Reject parent method table if possible.
6015         TriageTypeFromSoftBoundModule(pMT->GetParentMethodTable(), pSoftBoundModule);
6016
6017         // Reject all interfaces implemented by the type if possible.
6018         MethodTable::InterfaceMapIterator intIterator = pMT->IterateInterfaceMap();
6019         while (intIterator.Next())
6020         {
6021             TriageTypeFromSoftBoundModule(intIterator.GetInterface(), pSoftBoundModule);
6022         }
6023
6024         // It does not seem worth it to reject the remaining items 
6025         // expanded by CEEPreloader::ExpandTypeDependencies here.
6026     }
6027 }
6028
6029 #ifdef FEATURE_FULL_NGEN
6030 static TypeHandle TryToLoadTypeSpecHelper(Module * pModule, PCCOR_SIGNATURE pSig, ULONG cSig)
6031 {
6032     STANDARD_VM_CONTRACT;
6033
6034     TypeHandle th;
6035
6036     EX_TRY
6037     {
6038         SigPointer p(pSig, cSig);
6039         SigTypeContext typeContext;    // empty context is OK: encoding should not contain type variables.
6040
6041         th = p.GetTypeHandleThrowing(pModule, &typeContext, ClassLoader::DontLoadTypes);
6042     }
6043     EX_CATCH
6044     {
6045     }
6046     EX_END_CATCH(SwallowAllExceptions)
6047
6048     return th;
6049 }
6050
6051 void CEEPreloader::TriageTypeSpecsFromSoftBoundModule(Module * pSoftBoundModule)
6052 {
6053     STANDARD_VM_CONTRACT;
6054
6055     //
6056     // Reject all typespecs that are guranteed to be found in soft bound PZM
6057     //
6058
6059     IMDInternalImport *pInternalImport = pSoftBoundModule->GetMDImport();
6060
6061     HENUMInternalHolder hEnum(pInternalImport);
6062     hEnum.EnumAllInit(mdtTypeSpec);
6063
6064     mdToken tk;
6065     while (pInternalImport->EnumNext(&hEnum, &tk))
6066     {
6067         ULONG cSig;
6068         PCCOR_SIGNATURE pSig;
6069
6070         if (FAILED(pInternalImport->GetTypeSpecFromToken(tk, &pSig, &cSig)))
6071         {
6072             pSig = NULL;
6073             cSig = 0;
6074         }
6075
6076         // Check all types specs that do not contain variables
6077         if (SigPointer(pSig, cSig).IsPolyType(NULL) == hasNoVars)
6078         {
6079             TypeHandle th = TryToLoadTypeSpecHelper(pSoftBoundModule, pSig, cSig);
6080
6081             if (th.IsNull())
6082                 continue;
6083
6084             TriageTypeFromSoftBoundModule(th, pSoftBoundModule);
6085         }
6086     }
6087 }
6088
6089 void CEEPreloader::TriageSpeculativeType(TypeHandle th)
6090 {
6091     STANDARD_VM_CONTRACT;
6092
6093     // Nothing to do if we have rejected the type already
6094     if (m_rejectedTypes.Lookup(th) != NULL)
6095         return;
6096
6097     Module * pPreferredZapModule = Module::GetPreferredZapModuleForTypeHandle(th);
6098     BOOL fHardBoundPreferredZapModule = FALSE;
6099
6100     //
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
6103     //
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)
6107     {
6108         Module * hardBoundModule = (Module*)iter.GetValue();
6109         if (hardBoundModule->GetAvailableParamTypes()->ContainsValue(th))
6110         {
6111             m_rejectedTypes.Add(th);
6112             return;
6113         }
6114
6115         if (hardBoundModule == pPreferredZapModule)
6116         {
6117             fHardBoundPreferredZapModule = TRUE;
6118         }
6119     }
6120
6121     if (!fHardBoundPreferredZapModule && !pPreferredZapModule->AreTypeSpecsTriaged())
6122     {
6123         // Reject all types that are guaranteed to be instantiated in soft bound PZM
6124         TriageTypeSpecsFromSoftBoundModule(pPreferredZapModule);
6125         pPreferredZapModule->SetTypeSpecsTriaged();
6126
6127         if (m_rejectedTypes.Lookup(th) != NULL)
6128             return;
6129     }
6130
6131     // We have to no other option but to accept and expand the type
6132     ExpandTypeDependencies(th);
6133 }
6134
6135 void CEEPreloader::TriageSpeculativeInstantiations()
6136 {
6137     STANDARD_VM_CONTRACT;
6138
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++)
6142     {
6143         TriageSpeculativeType(m_speculativeTypes[i]);
6144     }
6145
6146     // We are done - the array of speculative types is no longer necessary
6147     m_speculativeTypes.Clear();
6148 }
6149 #endif // FEATURE_FULL_NGEN
6150
6151 BOOL CEEPreloader::TriageForZap(BOOL fAcceptIfNotSure, BOOL fExpandDependencies)
6152 {
6153     STANDARD_VM_CONTRACT;
6154
6155     DWORD dwNumTypes = m_image->GetModule()->GetAvailableParamTypes()->GetCount();
6156     DWORD dwNumMethods = m_image->GetModule()->GetInstMethodHashTable()->GetCount();
6157
6158     // Triage types
6159     {
6160         // Create a local copy in case the new elements are added to the hashtable during population
6161         InlineSArray<TypeHandle, 20> pTypes;
6162
6163         // Make sure the iterator is destroyed before there is a chance of loading new types
6164         {
6165             EETypeHashTable* pTable = m_image->GetModule()->GetAvailableParamTypes();
6166
6167             EETypeHashTable::Iterator it(pTable);
6168             EETypeHashEntry *pEntry;
6169             while (pTable->FindNext(&it, &pEntry))
6170             {
6171                 TypeHandle th = pEntry->GetTypeHandle();
6172                 if (m_acceptedTypes.Lookup(th) == NULL && m_rejectedTypes.Lookup(th) == NULL)
6173                     pTypes.Append(th);
6174             }
6175         }
6176
6177         for(COUNT_T i = 0; i < pTypes.GetCount(); i ++)
6178         {
6179             TriageTypeForZap(pTypes[i], fAcceptIfNotSure, fExpandDependencies);
6180         }
6181     }
6182
6183     // Triage methods
6184     {
6185         // Create a local copy in case the new elements are added to the hashtable during population
6186         InlineSArray<MethodDesc*, 20> pMethods;
6187
6188         // Make sure the iterator is destroyed before there is a chance of loading new methods
6189         {
6190             InstMethodHashTable* pTable = m_image->GetModule()->GetInstMethodHashTable();
6191
6192             InstMethodHashTable::Iterator it(pTable);
6193             InstMethodHashEntry *pEntry;
6194             while (pTable->FindNext(&it, &pEntry))
6195             {
6196                 MethodDesc* pMD = pEntry->GetMethod();
6197                 if (m_acceptedMethods.Lookup(pMD) == NULL && m_rejectedMethods.Lookup(pMD) == NULL)
6198                     pMethods.Append(pMD);
6199             }
6200         }
6201
6202         for(COUNT_T i = 0; i < pMethods.GetCount(); i ++)
6203         {
6204             TriageMethodForZap(pMethods[i], fAcceptIfNotSure, fExpandDependencies);
6205         }
6206     }
6207
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());
6211 }
6212
6213 void CEEPreloader::PrePrepareMethodIfNecessary(CORINFO_METHOD_HANDLE hMethod)
6214 {
6215     STANDARD_VM_CONTRACT;
6216
6217 }
6218
6219 static void SetStubMethodDescOnInteropMethodDesc(MethodDesc* pInteropMD, MethodDesc* pStubMD, bool fReverseStub)
6220 {
6221     CONTRACTL
6222     {
6223         THROWS;
6224         GC_TRIGGERS;
6225         MODE_ANY;
6226
6227         // We store NGENed stubs on these MethodDesc types
6228         PRECONDITION(pInteropMD->IsNDirect() || pInteropMD->IsComPlusCall() || pInteropMD->IsGenericComPlusCall() || pInteropMD->IsEEImpl());
6229     }
6230     CONTRACTL_END;
6231
6232     if (pInteropMD->IsNDirect())
6233     {
6234         _ASSERTE(!fReverseStub);
6235         NDirectMethodDesc* pNMD = (NDirectMethodDesc*)pInteropMD;
6236         pNMD->ndirect.m_pStubMD.SetValue(pStubMD);
6237     }
6238 #ifdef FEATURE_COMINTEROP
6239     else if (pInteropMD->IsComPlusCall() || pInteropMD->IsGenericComPlusCall())
6240     {
6241         _ASSERTE(!fReverseStub);
6242         ComPlusCallInfo *pComInfo = ComPlusCallInfo::FromMethodDesc(pInteropMD);
6243        pComInfo->m_pStubMD.SetValue(pStubMD);
6244     }
6245 #endif // FEATURE_COMINTEROP
6246     else if (pInteropMD->IsEEImpl())
6247     {
6248         DelegateEEClass* pDelegateClass = (DelegateEEClass*)pInteropMD->GetClass();
6249         if (fReverseStub)
6250         {
6251             pDelegateClass->m_pReverseStubMD = pStubMD;
6252         }
6253         else
6254         {
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())
6260             {
6261                 pDelegateClass->m_pComPlusCallInfo->m_pStubMD.SetValue(pStubMD);
6262             }
6263             else
6264 #endif // FEATURE_COMINTEROP
6265             {
6266                 pDelegateClass->m_pForwardStubMD = pStubMD;
6267             }
6268         }
6269     }
6270     else
6271     {
6272         UNREACHABLE_MSG("unexpected type of MethodDesc");
6273     }
6274 }
6275
6276 MethodDesc * CEEPreloader::CompileMethodStubIfNeeded(
6277         MethodDesc *pMD,
6278         MethodDesc *pStubMD,
6279         ICorCompilePreloader::CORCOMPILE_CompileStubCallback pfnCallback,
6280         LPVOID pCallbackContext)
6281 {
6282     STANDARD_VM_CONTRACT;
6283
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));
6286
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())
6290     {
6291         if (!pStubMD->AsDynamicMethodDesc()->GetILStubResolver()->IsCompiled())
6292         {
6293             CORJIT_FLAGS jitFlags = pStubMD->AsDynamicMethodDesc()->GetILStubResolver()->GetJitFlags();
6294
6295             pfnCallback(pCallbackContext, (CORINFO_METHOD_HANDLE)pStubMD, jitFlags);
6296         }
6297
6298 #ifndef FEATURE_FULL_NGEN // Deduplication
6299         const DuplicateMethodEntry * pDuplicate = m_duplicateMethodsHash.LookupPtr(pStubMD);
6300         if (pDuplicate != NULL)
6301             return pDuplicate->pDuplicateMD;
6302 #endif
6303     }
6304
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)
6308         pStubMD=NULL;
6309
6310     return pStubMD;
6311 }
6312
6313 void CEEPreloader::GenerateMethodStubs(
6314         CORINFO_METHOD_HANDLE hMethod,
6315         bool                  fNgenProfilerImage,
6316         CORCOMPILE_CompileStubCallback pfnCallback,
6317         LPVOID                pCallbackContext)
6318 {
6319     CONTRACTL
6320     {
6321         STANDARD_VM_CHECK;
6322         PRECONDITION(hMethod != NULL && pfnCallback != NULL);
6323     }
6324     CONTRACTL_END;
6325
6326     MethodDesc* pMD = GetMethod(hMethod);
6327     MethodDesc* pStubMD = NULL;
6328
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())
6333         return;
6334
6335     DWORD dwNGenStubFlags = NDIRECTSTUB_FL_NGENEDSTUB;
6336
6337     if (fNgenProfilerImage)
6338         dwNGenStubFlags |= NDIRECTSTUB_FL_NGENEDSTUBFORPROFILING;
6339
6340     //
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
6343     //    
6344     EX_TRY
6345     {
6346         //
6347         // Take care of forward stubs
6348         //            
6349         if (pMD->IsNDirect())
6350         {
6351             NDirectMethodDesc* pNMD = (NDirectMethodDesc*)pMD;
6352             PInvokeStaticSigInfo sigInfo;
6353             NDirect::PopulateNDirectMethodDesc(pNMD, &sigInfo);
6354             pStubMD = NDirect::GetILStubMethodDesc((NDirectMethodDesc*)pMD, &sigInfo, dwNGenStubFlags);
6355         }
6356 #ifdef FEATURE_COMINTEROP
6357         else if (pMD->IsComPlusCall() || pMD->IsGenericComPlusCall())
6358         {
6359             if (MethodNeedsForwardComStub(pMD, m_image))
6360             {
6361                 // Look for predefined IL stubs in forward com interop scenario. 
6362                 // If we've found a stub, that's what we'll use
6363                 DWORD dwStubFlags;
6364                 ComPlusCall::PopulateComPlusCallMethodDesc(pMD, &dwStubFlags);
6365                 if (FAILED(FindPredefinedILStubMethod(pMD, dwStubFlags, &pStubMD)))
6366                 {                    
6367                     pStubMD = ComPlusCall::GetILStubMethodDesc(pMD, dwStubFlags | dwNGenStubFlags);
6368                 }
6369             }
6370         }
6371 #endif // FEATURE_COMINTEROP
6372         else if (pMD->IsEEImpl())
6373         {
6374             MethodTable* pMT = pMD->GetMethodTable();
6375             CONSISTENCY_CHECK(pMT->IsDelegate());
6376
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
6382                 )
6383             {
6384                 if (COMDelegate::IsDelegateInvokeMethod(pMD)) // build forward stub
6385                 {
6386 #ifdef FEATURE_COMINTEROP
6387                     if ((pMT->IsProjectedFromWinRT() || WinRTTypeNameConverter::IsRedirectedType(pMT)) &&
6388                         (!pMT->HasInstantiation() || pMT->SupportsGenericInterop(TypeHandle::Interop_ManagedToNative))) // filter out shared generics
6389                     {
6390                         // Build the stub for all WinRT delegates, these will definitely be used for interop.
6391                         if (pMT->IsLegalNonArrayWinRTType())
6392                         {
6393                             COMDelegate::PopulateComPlusCallInfo(pMT);
6394                             pStubMD = COMDelegate::GetILStubMethodDesc((EEImplMethodDesc *)pMD, dwNGenStubFlags);
6395                         }
6396                     }
6397                     else
6398 #endif // FEATURE_COMINTEROP
6399                     {
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.
6402
6403                         if (S_OK == pMT->GetMDImport()->GetCustomAttributeByName(
6404                             pMT->GetCl(), g_UnmanagedFunctionPointerAttribute, NULL, NULL))
6405                         {
6406                             pStubMD = COMDelegate::GetILStubMethodDesc((EEImplMethodDesc *)pMD, dwNGenStubFlags);
6407                         }
6408                     }
6409                 }
6410             }
6411         }
6412
6413         // compile the forward stub
6414         if (pStubMD != NULL)
6415         {
6416             pStubMD = CompileMethodStubIfNeeded(pMD, pStubMD, pfnCallback, pCallbackContext);
6417
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)
6421             {
6422                  SetStubMethodDescOnInteropMethodDesc(pMD, pStubMD, false /* fReverseStub */);
6423                  pStubMD = NULL;
6424             }
6425
6426         }
6427     }
6428     EX_CATCH
6429     {
6430         LOG((LF_ZAP, LL_WARNING, "NGEN_ILSTUB: Generating forward interop stub FAILED: %s::%s\n", pMD->m_pszDebugClassName, pMD->m_pszDebugMethodName));
6431     }
6432     EX_END_CATCH(RethrowTransientExceptions);
6433
6434     //
6435     // Now take care of reverse P/Invoke stubs for delegates
6436     //
6437     if (pMD->IsEEImpl() && COMDelegate::IsDelegateInvokeMethod(pMD))
6438     {
6439         // Reverse P/Invoke is not supported for generic methods and WinRT delegates
6440         if (!pMD->HasClassOrMethodInstantiation() && !pMD->GetMethodTable()->IsProjectedFromWinRT())
6441         {
6442             EX_TRY
6443             {
6444 #ifdef _TARGET_X86_
6445                 // on x86, we call the target directly if Invoke has a no-marshal signature
6446                 if (NDirect::MarshalingRequired(pMD))
6447 #endif // _TARGET_X86_
6448                 {
6449                     PInvokeStaticSigInfo sigInfo(pMD);
6450                     pStubMD = UMThunkMarshInfo::GetILStubMethodDesc(pMD, &sigInfo, NDIRECTSTUB_FL_DELEGATE | dwNGenStubFlags);
6451
6452                     if (pStubMD != NULL)
6453                     {
6454                         // compile the reverse stub
6455                         pStubMD = CompileMethodStubIfNeeded(pMD, pStubMD, pfnCallback, pCallbackContext);
6456
6457                         // We store the MethodDesc of the Stub on the DelegateEEClass
6458                         if (pStubMD != NULL)
6459                         {
6460                             SetStubMethodDescOnInteropMethodDesc(pMD, pStubMD, true /* fReverseStub */);
6461                         }
6462                     }
6463                 }
6464             }
6465             EX_CATCH
6466             {
6467                 LOG((LF_ZAP, LL_WARNING, "NGEN_ILSTUB: Generating reverse interop stub for delegate FAILED: %s::%s\n", pMD->m_pszDebugClassName, pMD->m_pszDebugMethodName));
6468             }
6469             EX_END_CATCH(RethrowTransientExceptions);
6470         }
6471     }
6472
6473 #ifdef FEATURE_COMINTEROP
6474     //
6475     // And finally generate reverse COM stubs
6476     //
6477     EX_TRY
6478     {
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))
6483         {
6484             // initialize ComCallMethodDesc
6485             ComCallMethodDesc ccmd;
6486             ComCallMethodDescHolder ccmdHolder(&ccmd);
6487             ccmd.InitMethod(pMD, NULL);
6488
6489             // generate the IL stub
6490             DWORD dwStubFlags;
6491             ComCall::PopulateComCallMethodDesc(&ccmd, &dwStubFlags);
6492             pStubMD = ComCall::GetILStubMethodDesc(pMD, dwStubFlags | dwNGenStubFlags);
6493
6494             if (pStubMD != NULL)
6495             {
6496                 // compile the reverse stub
6497                 pStubMD = CompileMethodStubIfNeeded(pMD, pStubMD, pfnCallback, pCallbackContext);
6498
6499                 if (pStubMD != NULL)
6500                 {
6501                     // store the stub in a hash table on the module
6502                     m_image->GetModule()->GetStubMethodHashTable()->InsertMethodDesc(pMD, pStubMD);
6503                 }
6504             }
6505         }
6506     }
6507     EX_CATCH
6508     {
6509         LOG((LF_ZAP, LL_WARNING, "NGEN_ILSTUB: Generating reverse interop stub FAILED: %s::%s\n", pMD->m_pszDebugClassName, pMD->m_pszDebugMethodName));
6510     }
6511     EX_END_CATCH(RethrowTransientExceptions);
6512 #endif // FEATURE_COMINTEROP
6513 }
6514
6515 bool CEEPreloader::IsDynamicMethod(CORINFO_METHOD_HANDLE hMethod)
6516 {
6517     STANDARD_VM_CONTRACT;
6518
6519     MethodDesc* pMD = GetMethod(hMethod);
6520
6521     if (pMD)
6522     {
6523         return pMD->IsDynamicMethod();
6524     }
6525
6526     return false;
6527 }
6528
6529 // Set method profiling flags for layout of EE datastructures
6530 void CEEPreloader::SetMethodProfilingFlags(CORINFO_METHOD_HANDLE hMethod, DWORD flags)
6531 {
6532     STANDARD_VM_CONTRACT;
6533
6534     _ASSERTE(hMethod != NULL);
6535     _ASSERTE(flags != 0);
6536
6537     return m_image->SetMethodProfilingFlags(GetMethod(hMethod), flags);
6538 }
6539
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.
6544 //
6545 // This is used to rule out both ngen-hardbinds and intra-ngen-module
6546 // direct calls.
6547 //
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.
6552 //
6553 // callerHnd=NULL implies any/unspecified caller.
6554 //
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
6557
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*/)
6563 {
6564     STANDARD_VM_CONTRACT;
6565
6566     bool result = false;
6567
6568     COOPERATIVE_TRANSITION_BEGIN();
6569
6570     MethodDesc *  calleeMD    = (MethodDesc *)calleeHnd;
6571     MethodDesc *  callerMD    = (MethodDesc *)callerHnd;
6572
6573     {
6574         result = calleeMD->CanSkipDoPrestub(callerMD, pReason, accessFlags);
6575     }
6576
6577     COOPERATIVE_TRANSITION_END();
6578
6579     return result;
6580 }
6581
6582 CORINFO_METHOD_HANDLE CEEPreloader::LookupMethodDef(mdMethodDef token)
6583 {
6584     STANDARD_VM_CONTRACT;
6585     MethodDesc *resultMD = nullptr;
6586
6587     EX_TRY
6588     {
6589         MethodDesc *pMD = MemberLoader::GetMethodDescFromMethodDef(m_image->GetModule(), token, FALSE);
6590
6591         if (IsReadyToRunCompilation() && pMD->HasClassOrMethodInstantiation())
6592         {
6593             _ASSERTE(IsCompilationProcess() && pMD->GetModule_NoLogging() == GetAppDomain()->ToCompilationDomain()->GetTargetModule());
6594         }
6595
6596         resultMD = pMD->FindOrCreateTypicalSharedInstantiation();
6597     }
6598     EX_CATCH
6599     {
6600         this->Error(token, GET_EXCEPTION());
6601     }
6602     EX_END_CATCH(SwallowAllExceptions)
6603
6604     return CORINFO_METHOD_HANDLE(resultMD);
6605 }
6606
6607 bool CEEPreloader::GetMethodInfo(mdMethodDef token, CORINFO_METHOD_HANDLE ftnHnd, CORINFO_METHOD_INFO * methInfo)
6608 {
6609     STANDARD_VM_CONTRACT;
6610     bool result = false;
6611
6612     EX_TRY
6613     {
6614         result = GetZapJitInfo()->getMethodInfo(ftnHnd, methInfo);
6615     }
6616     EX_CATCH
6617     {
6618         result = false;
6619         this->Error(token, GET_EXCEPTION());
6620     }
6621     EX_END_CATCH(SwallowAllExceptions)
6622
6623     return result;
6624 }
6625
6626 static BOOL MethodIsVisibleOutsideItsAssembly(DWORD dwMethodAttr)
6627 {
6628     LIMITED_METHOD_CONTRACT;
6629     return (IsMdPublic(dwMethodAttr) ||
6630         IsMdFamORAssem(dwMethodAttr) ||
6631         IsMdFamily(dwMethodAttr));
6632 }
6633
6634 static BOOL ClassIsVisibleOutsideItsAssembly(DWORD dwClassAttr, BOOL fIsGlobalClass)
6635 {
6636     LIMITED_METHOD_CONTRACT;
6637
6638     if (fIsGlobalClass)
6639     {
6640         return TRUE;
6641     }
6642
6643     return (IsTdPublic(dwClassAttr) ||
6644         IsTdNestedPublic(dwClassAttr) ||
6645         IsTdNestedFamily(dwClassAttr) ||
6646         IsTdNestedFamORAssem(dwClassAttr));
6647 }
6648
6649 static BOOL MethodIsVisibleOutsideItsAssembly(MethodDesc * pMD)
6650 {
6651     LIMITED_METHOD_CONTRACT;
6652
6653     MethodTable * pMT = pMD->GetMethodTable();
6654
6655     if (!ClassIsVisibleOutsideItsAssembly(pMT->GetAttrClass(), pMT->IsGlobalClass()))
6656         return FALSE;
6657
6658     return MethodIsVisibleOutsideItsAssembly(pMD->GetAttrs());
6659 }
6660
6661 CorCompileILRegion CEEPreloader::GetILRegion(mdMethodDef token)
6662 {
6663     STANDARD_VM_CONTRACT;
6664
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();
6669
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;
6673
6674     EX_TRY
6675     {
6676         MethodDesc *pMD = m_image->GetModule()->LookupMethodDef(token);
6677
6678         if (pMD == NULL || !pMD->GetMethodTable()->IsFullyLoaded())
6679         {
6680             // Something is completely wrong - use the default
6681         }
6682         else
6683         if (m_image->IsStored(pMD))
6684         {
6685             if (pMD->IsNotInline())
6686             {
6687                 if (pMD->HasClassOrMethodInstantiation())
6688                 {
6689                     region = CORCOMPILE_ILREGION_GENERICS;
6690                 }
6691                 else
6692                 {
6693                     region = CORCOMPILE_ILREGION_COLD;
6694                 }
6695             }
6696             else
6697             if (MethodIsVisibleOutsideItsAssembly(pMD))
6698             {
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;
6702             }
6703             else
6704             {
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;
6708             }
6709         }
6710     }
6711     EX_CATCH
6712     {
6713     }
6714     EX_END_CATCH(SwallowAllExceptions)
6715
6716     return region;
6717 }
6718
6719
6720 CORINFO_METHOD_HANDLE CEEPreloader::FindMethodForProfileEntry(CORBBTPROF_BLOB_PARAM_SIG_ENTRY * profileBlobEntry)
6721 {
6722     STANDARD_VM_CONTRACT;
6723     MethodDesc *  pMethod = nullptr;
6724
6725     _ASSERTE(profileBlobEntry->blob.type == ParamMethodSpec);
6726
6727     if (PartialNGenStressPercentage() != 0)
6728         return CORINFO_METHOD_HANDLE( NULL );
6729
6730     Module * pModule = GetAppDomain()->ToCompilationDomain()->GetTargetModule();
6731     pMethod = pModule->LoadIBCMethodHelper(m_image, profileBlobEntry);
6732    
6733     return CORINFO_METHOD_HANDLE( pMethod );
6734 }
6735
6736 void CEEPreloader::ReportInlining(CORINFO_METHOD_HANDLE inliner, CORINFO_METHOD_HANDLE inlinee)
6737 {
6738     STANDARD_VM_CONTRACT;
6739     m_image->ReportInlining(inliner, inlinee);
6740 }
6741
6742 void CEEPreloader::Link()
6743 {
6744     STANDARD_VM_CONTRACT;
6745
6746     COOPERATIVE_TRANSITION_BEGIN();
6747
6748     m_image->PreSave();
6749
6750     m_image->GetModule()->Save(m_image);
6751     m_image->GetModule()->Arrange(m_image);
6752     m_image->GetModule()->Fixup(m_image);
6753
6754     m_image->PostSave();
6755
6756     COOPERATIVE_TRANSITION_END();
6757 }
6758
6759 void CEEPreloader::FixupRVAs()
6760 {
6761     STANDARD_VM_CONTRACT;
6762
6763     COOPERATIVE_TRANSITION_BEGIN();
6764
6765     m_image->FixupRVAs();
6766
6767     COOPERATIVE_TRANSITION_END();
6768 }
6769
6770 void CEEPreloader::SetRVAsForFields(IMetaDataEmit * pEmit)
6771 {
6772     STANDARD_VM_CONTRACT;
6773
6774     COOPERATIVE_TRANSITION_BEGIN();
6775
6776     m_image->SetRVAsForFields(pEmit);
6777
6778     COOPERATIVE_TRANSITION_END();
6779 }
6780
6781 void CEEPreloader::GetRVAFieldData(mdFieldDef fd, PVOID * ppData, DWORD * pcbSize, DWORD * pcbAlignment)
6782 {
6783     STANDARD_VM_CONTRACT;
6784
6785     COOPERATIVE_TRANSITION_BEGIN();
6786
6787     FieldDesc * pFD = m_image->GetModule()->LookupFieldDef(fd);
6788     if (pFD == NULL)
6789         ThrowHR(COR_E_TYPELOAD);
6790
6791     _ASSERTE(pFD->IsRVA());
6792
6793     UINT size = pFD->LoadSize();
6794
6795     // 
6796     // Compute an alignment for the data based on the alignment
6797     // of the RVA.  We'll align up to 8 bytes.
6798     //
6799
6800     UINT align = 1;
6801     DWORD rva = pFD->GetOffset();
6802     DWORD rvaTemp = rva;   
6803
6804     while ((rvaTemp&1) == 0 && align < 8 && align < size)
6805     {
6806         align <<= 1;
6807         rvaTemp >>= 1;
6808     }
6809
6810
6811     *ppData = pFD->GetStaticAddressHandle(NULL);
6812     *pcbSize = size;
6813     *pcbAlignment = align;
6814
6815     COOPERATIVE_TRANSITION_END();
6816 }
6817
6818 ULONG CEEPreloader::Release()
6819 {
6820     CONTRACTL {
6821         NOTHROW;
6822         GC_NOTRIGGER;
6823         MODE_ANY;
6824     } CONTRACTL_END;
6825
6826     delete this;
6827     return 0;
6828 }
6829
6830 #ifdef FEATURE_READYTORUN_COMPILER
6831 void CEEPreloader::GetSerializedInlineTrackingMap(SBuffer* pBuffer)
6832 {
6833     InlineTrackingMap * pInlineTrackingMap = m_image->GetInlineTrackingMap();
6834     PersistentInlineTrackingMapR2R::Save(m_image->GetHeap(), pBuffer, pInlineTrackingMap);
6835 }
6836 #endif
6837
6838 void CEEPreloader::Error(mdToken token, Exception * pException)
6839 {
6840     STANDARD_VM_CONTRACT;
6841
6842     HRESULT hr = pException->GetHR();
6843     UINT    resID = 0;
6844
6845     StackSString msg;
6846
6847 #ifdef CROSSGEN_COMPILE
6848     pException->GetMessage(msg);
6849
6850     // Do we have an EEException with a resID?
6851     if (EEMessageException::IsEEMessageException(pException))
6852     {
6853         EEMessageException * pEEMessageException = (EEMessageException *) pException;
6854         resID = pEEMessageException->GetResID();
6855     }
6856 #else
6857     {
6858         GCX_COOP();
6859
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);
6862
6863         if (throwable != NULL)
6864         {
6865             GetExceptionMessage(throwable, msg);
6866         }
6867         else
6868         {
6869             pException->GetMessage(msg);
6870         }
6871     }
6872 #endif
6873     
6874     m_pData->Error(token, hr, resID, msg.GetUnicode());
6875 }
6876
6877 CEEInfo *g_pCEEInfo = NULL;
6878
6879 ICorDynamicInfo * __stdcall GetZapJitInfo()
6880 {
6881     STANDARD_VM_CONTRACT;
6882
6883     if (g_pCEEInfo == NULL)
6884     {
6885         CEEInfo * p = new CEEInfo();
6886         if (InterlockedCompareExchangeT(&g_pCEEInfo, p, NULL) != NULL)
6887             delete p;
6888     }
6889
6890     return g_pCEEInfo;
6891 }
6892
6893 CEECompileInfo *g_pCEECompileInfo = NULL;
6894
6895 ICorCompileInfo * __stdcall GetCompileInfo()
6896 {
6897     STANDARD_VM_CONTRACT;
6898
6899     if (g_pCEECompileInfo == NULL)
6900     {
6901         CEECompileInfo * p = new CEECompileInfo();
6902         if (InterlockedCompareExchangeT(&g_pCEECompileInfo, p, NULL) != NULL)
6903             delete p;
6904     }
6905
6906     return g_pCEECompileInfo;
6907 }
6908
6909 //
6910 // CompilationDomain
6911 //
6912
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),
6922     m_pEmit(NULL),
6923     m_pDependencyRefSpecs(NULL),
6924     m_pDependencies(NULL),
6925     m_cDependenciesCount(0),
6926     m_cDependenciesAlloc(0)
6927 {
6928     STANDARD_VM_CONTRACT;
6929
6930 }
6931
6932 void CompilationDomain::ReleaseDependencyEmitter()
6933 {
6934     m_pDependencyRefSpecs.Release();
6935
6936     m_pEmit.Release();
6937 }
6938
6939 CompilationDomain::~CompilationDomain()
6940 {
6941     CONTRACTL
6942     {
6943         NOTHROW;
6944         GC_TRIGGERS;
6945         MODE_ANY;
6946     }
6947     CONTRACTL_END;
6948
6949     if (m_pDependencies != NULL)
6950         delete [] m_pDependencies;
6951
6952     ReleaseDependencyEmitter();
6953
6954     for (unsigned i = 0; i < m_rRefCaches.Size(); i++)
6955     {
6956         delete m_rRefCaches[i];
6957         m_rRefCaches[i]=NULL;
6958     }
6959
6960 }
6961
6962 void CompilationDomain::Init()
6963 {
6964     STANDARD_VM_CONTRACT;
6965
6966 #ifndef CROSSGEN_COMPILE
6967     AppDomain::Init();
6968 #endif
6969
6970 #ifndef CROSSGEN_COMPILE
6971     // allocate a Virtual Call Stub Manager for the compilation domain
6972     InitVSD();
6973 #endif
6974
6975     SetCompilationDomain();
6976
6977
6978 #ifdef _DEBUG 
6979     g_pConfig->DisableGenerateStubForHost();
6980 #endif
6981 }
6982
6983 HRESULT CompilationDomain::AddDependencyEntry(PEAssembly *pFile,
6984                                            mdAssemblyRef ref,
6985                                            mdAssemblyRef def)
6986 {
6987 #ifdef _DEBUG
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;
6991     if (threadId == 0)
6992     {
6993         InterlockedCompareExchange(&threadId, GetCurrentThreadId(), 0);
6994     }
6995     _ASSERTE((LONG)GetCurrentThreadId() == threadId);
6996 #endif // _DEBUG
6997
6998     _ASSERTE((pFile == NULL) == (def == mdAssemblyRefNil));
6999
7000     if (m_cDependenciesCount == m_cDependenciesAlloc)
7001     {
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;
7006
7007         // Grow m_pDependencies
7008
7009         NewArrayHolder<CORCOMPILE_DEPENDENCY> pNewDependencies(new CORCOMPILE_DEPENDENCY[cNewDependenciesAlloc]);
7010         {
7011             // This block must execute transactionally. No throwing allowed. No bailing allowed.
7012             FAULT_FORBID();
7013
7014             memset(pNewDependencies,  0, cNewDependenciesAlloc*sizeof(CORCOMPILE_DEPENDENCY));
7015
7016             if (m_pDependencies)
7017             {
7018                 memcpy(pNewDependencies, m_pDependencies,
7019                        m_cDependenciesCount*sizeof(CORCOMPILE_DEPENDENCY));
7020     
7021                 delete [] m_pDependencies;
7022             }
7023     
7024             m_pDependencies = pNewDependencies.Extract();
7025             m_cDependenciesAlloc = cNewDependenciesAlloc;
7026         }
7027     }
7028
7029     CORCOMPILE_DEPENDENCY *pDependency = &m_pDependencies[m_cDependenciesCount++];
7030
7031     // Clear memory so that we won't write random data into the zapped file
7032     ZeroMemory(pDependency, sizeof(CORCOMPILE_DEPENDENCY));
7033
7034     pDependency->dwAssemblyRef = ref;
7035
7036     pDependency->dwAssemblyDef = def;
7037
7038     pDependency->signNativeImage = INVALID_NGEN_SIGNATURE;
7039
7040     if (pFile)
7041     {
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);
7045
7046
7047
7048         //
7049         // This is done in CompilationDomain::CanEagerBindToZapFile with full support for hardbinding
7050         //
7051         if (pFile->IsSystem() && pFile->HasNativeImage())
7052         {
7053             CORCOMPILE_VERSION_INFO * pNativeVersion = pFile->GetLoadedNative()->GetNativeVersionInfo();
7054             pDependency->signNativeImage = pNativeVersion->signature;
7055         }
7056
7057     }
7058
7059     return S_OK;
7060 }
7061
7062 HRESULT CompilationDomain::AddDependency(AssemblySpec *pRefSpec,
7063                                          PEAssembly * pFile)
7064 {
7065     HRESULT hr;
7066
7067     //
7068     // Record the dependency
7069     //
7070
7071     // This assert prevents dependencies from silently being loaded without being recorded.
7072     _ASSERTE(m_pEmit);
7073
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.)
7077     AssemblySpec spec;
7078     if (pRefSpec->IsMscorlib())
7079     {
7080         _ASSERTE(pFile); // mscorlib had better not be missing
7081         if (!pFile)
7082             return E_UNEXPECTED;
7083
7084         // Don't store a binding from mscorlib to itself.
7085         if (m_pTargetAssembly == SystemDomain::SystemAssembly())
7086             return S_OK;
7087
7088         spec.InitializeSpec(pFile);
7089         pRefSpec = &spec;
7090     }
7091     else if (m_pTargetAssembly == NULL && pFile)
7092     {
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())
7099         {
7100             spec.ConvertPublicKeyToToken();
7101         }
7102         pRefSpec = &spec;
7103     }
7104     else if (pRefSpec->IsStrongNamed() && pRefSpec->HasPublicKey())
7105     {
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();
7110         pRefSpec = &spec;
7111     }
7112
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())
7117     {
7118         // Successful bind of a reference with a non-unique assembly identity.
7119         _ASSERTE(pRefSpec->IsContentType_WindowsRuntime());
7120
7121         AssemblySpec defSpec;
7122         if (pFile != NULL)
7123         {
7124             defSpec.InitializeSpec(pFile);
7125
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;
7132         }
7133
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)
7139         {
7140             mdAssemblyRef refToken = mdAssemblyRefNil;
7141             IfFailRet(pRefSpec->EmitToken(m_pEmit, &refToken, TRUE, TRUE));
7142
7143             mdAssemblyRef defToken = mdAssemblyRefNil;
7144             if (pFile != NULL)
7145             {
7146                 IfFailRet(defSpec.EmitToken(m_pEmit, &defToken, TRUE, TRUE));
7147
7148                 NewHolder<AssemblySpec> pNewDefSpec = new AssemblySpec();
7149                 pNewDefSpec->CopyFrom(&defSpec);
7150                 pNewDefSpec->CloneFields();
7151
7152                 NewHolder<AssemblySpec> pNewRefSpec = new AssemblySpec();
7153                 pNewRefSpec->CopyFrom(pRefSpec);
7154                 pNewRefSpec->CloneFields();
7155
7156                 _ASSERTE(m_dependencyDefRefMap.LookupPtr(pNewDefSpec) == NULL);
7157
7158                 AssemblySpecDefRefMapEntry e;
7159                 e.m_pDef = pNewDefSpec;
7160                 e.m_pRef = pNewRefSpec;
7161                 m_dependencyDefRefMap.Add(e);
7162
7163                 pNewDefSpec.SuppressRelease();
7164                 pNewRefSpec.SuppressRelease();
7165             }
7166
7167             IfFailRet(AddDependencyEntry(pFile, refToken, defToken));
7168         }
7169     }
7170     else
7171 #endif // FEATURE_COMINTEROP
7172     {
7173         //
7174         // See if we've already added the contents of the ref
7175         // Else, emit token for the ref
7176         //
7177
7178         if (m_pDependencyRefSpecs->Store(pRefSpec))
7179             return S_OK;
7180
7181         mdAssemblyRef refToken;
7182         IfFailRet(pRefSpec->EmitToken(m_pEmit, &refToken));
7183
7184         //
7185         // Make a spec for the bound assembly
7186         //
7187
7188         mdAssemblyRef defToken = mdAssemblyRefNil;
7189
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
7195         if (pFile)
7196         {
7197             AssemblySpec assemblySpec;
7198             assemblySpec.InitializeSpec(pFile);
7199
7200             IfFailRet(assemblySpec.EmitToken(m_pEmit, &defToken));
7201         }
7202
7203         //
7204         // Add the entry.  Include the PEFile if we are not doing explicit bindings.
7205         //
7206
7207         IfFailRet(AddDependencyEntry(pFile, refToken, defToken));
7208     }
7209
7210     return S_OK;
7211 }
7212
7213 //----------------------------------------------------------------------------
7214 AssemblySpec* CompilationDomain::FindAssemblyRefSpecForDefSpec(
7215     AssemblySpec* pDefSpec)
7216 {
7217     WRAPPER_NO_CONTRACT;
7218
7219     if (pDefSpec == nullptr)
7220         return nullptr;
7221
7222     const AssemblySpecDefRefMapEntry * pEntry = m_dependencyDefRefMap.LookupPtr(pDefSpec);
7223     _ASSERTE(pEntry != NULL);
7224
7225     return (pEntry != NULL) ? pEntry->m_pRef : NULL;
7226 }
7227
7228
7229 //----------------------------------------------------------------------------
7230 // Is it OK to embed direct pointers to an ngen dependency?
7231 // true if hardbinding is OK, false otherwise
7232 //
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?
7239
7240 BOOL CompilationDomain::CanEagerBindToZapFile(Module *targetModule, BOOL limitToHardBindList)
7241 {
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)
7246     {
7247         return TRUE;
7248     }
7249
7250     //
7251     // CoreCLR does not have attributes for fine grained eager binding control.
7252     // We hard bind to mscorlib.dll only.
7253     //
7254     return targetModule->IsSystem();
7255 }
7256
7257
7258 void CompilationDomain::SetTarget(Assembly *pAssembly, Module *pModule)
7259 {
7260     STANDARD_VM_CONTRACT;
7261
7262     m_pTargetAssembly = pAssembly;
7263     m_pTargetModule = pModule;
7264 }
7265
7266 void CompilationDomain::SetTargetImage(DataImage *pImage, CEEPreloader * pPreloader)
7267 {
7268     STANDARD_VM_CONTRACT;
7269
7270     m_pTargetImage = pImage;
7271     m_pTargetPreloader = pPreloader;
7272
7273     _ASSERTE(pImage->GetModule() == GetTargetModule());
7274 }
7275
7276 void ReportMissingDependency(Exception * e)
7277 {
7278     // Avoid duplicate error messages
7279     if (FAILED(g_hrFatalError))
7280         return;
7281
7282     SString s;
7283
7284     e->GetMessage(s);
7285     GetSvcLogger()->Printf(LogLevel_Error, W("Error: %s\n"), s.GetUnicode());
7286
7287     g_hrFatalError = COR_E_FILELOAD;
7288 }
7289
7290 PEAssembly *CompilationDomain::BindAssemblySpec(
7291     AssemblySpec *pSpec,
7292     BOOL fThrowOnFileNotFound,
7293     BOOL fRaisePrebindEvents,
7294     StackCrawlMark *pCallerStackMark,
7295     BOOL fUseHostBinderIfAvailable)
7296 {
7297     PEAssembly *pFile = NULL;
7298     //
7299     // Do the binding
7300     //
7301
7302     EX_TRY
7303     {
7304         //
7305         // Use normal binding rules
7306         // (possibly with our custom IApplicationContext)
7307         //
7308         pFile = AppDomain::BindAssemblySpec(
7309             pSpec,
7310             fThrowOnFileNotFound,
7311             fRaisePrebindEvents,
7312             pCallerStackMark,
7313             fUseHostBinderIfAvailable);
7314     }
7315     EX_HOOK
7316     {
7317         if (!g_fNGenMissingDependenciesOk)
7318         {
7319             ReportMissingDependency(GET_EXCEPTION());
7320             EX_RETHROW;
7321         }
7322
7323         //
7324         // Record missing dependencies
7325         //
7326 #ifdef FEATURE_COMINTEROP                
7327         if (!g_fNGenWinMDResilient || pSpec->HasUniqueIdentity())
7328 #endif
7329         {
7330             IfFailThrow(AddDependency(pSpec, NULL));
7331         }
7332     }
7333     EX_END_HOOK
7334
7335 #ifdef FEATURE_COMINTEROP                
7336     if (!g_fNGenWinMDResilient || pSpec->HasUniqueIdentity())
7337 #endif
7338     {
7339         IfFailThrow(AddDependency(pSpec, pFile));
7340     }
7341
7342     return pFile;
7343 }
7344
7345 HRESULT
7346     CompilationDomain::SetContextInfo(LPCWSTR path, BOOL isExe)
7347 {
7348     STANDARD_VM_CONTRACT;
7349
7350     HRESULT hr = S_OK;
7351
7352     COOPERATIVE_TRANSITION_BEGIN();
7353
7354
7355     COOPERATIVE_TRANSITION_END();
7356
7357     return hr;
7358 }
7359
7360 void CompilationDomain::SetDependencyEmitter(IMetaDataAssemblyEmit *pEmit)
7361 {
7362     STANDARD_VM_CONTRACT;
7363
7364     pEmit->AddRef();
7365     m_pEmit = pEmit;
7366
7367     m_pDependencyRefSpecs = new AssemblySpecHash();
7368 }
7369
7370
7371 HRESULT
7372     CompilationDomain::GetDependencies(CORCOMPILE_DEPENDENCY **ppDependencies,
7373                                        DWORD *pcDependencies)
7374 {
7375     STANDARD_VM_CONTRACT;
7376
7377
7378     //
7379     // Return the bindings.
7380     //
7381
7382     *ppDependencies = m_pDependencies;
7383     *pcDependencies = m_cDependenciesCount;
7384
7385     // Cannot add any more dependencies
7386     ReleaseDependencyEmitter();
7387
7388     return S_OK;
7389 }
7390
7391
7392 #ifdef CROSSGEN_COMPILE
7393 HRESULT CompilationDomain::SetPlatformWinmdPaths(LPCWSTR pwzPlatformWinmdPaths)
7394 {
7395     STANDARD_VM_CONTRACT;
7396
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();
7400
7401     SString strPaths(pwzPlatformWinmdPaths);
7402     if (!strPaths.IsEmpty())
7403     {
7404         for (SString::Iterator i = strPaths.Begin(); i != strPaths.End(); )
7405         {
7406             // Skip any leading spaces or semicolons
7407             if (strPaths.Skip(i, W(';')))
7408             {
7409                 continue;
7410             }
7411         
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(';')))
7415             {
7416                 iNext = iEnd + 1;
7417             }
7418             else
7419             {
7420                 iNext = iEnd = strPaths.End();
7421             }
7422         
7423             _ASSERTE(i < iEnd);
7424             if(i != iEnd)
7425             {
7426                 saPaths->Append(SString(strPaths, i, iEnd));
7427             }
7428             i = iNext;
7429         }
7430     }
7431     Crossgen::SetFirstPartyWinMDPaths(saPaths);
7432 #endif // FEATURE_COMINTEROP
7433
7434     return S_OK;
7435 }
7436 #endif // CROSSGEN_COMPILE
7437
7438
7439 #endif // FEATURE_PREJIT