Remove always defined FEATURE_CORECLR
[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 "security.h"
26 #include "eeconfig.h"
27 #include "zapsig.h"
28 #include "gcrefmap.h"
29
30
31 #include "virtualcallstub.h"
32 #include "typeparse.h"
33 #include "typestring.h"
34 #include "constrainedexecutionregion.h"
35 #include "dllimport.h"
36 #include "comdelegate.h"
37 #include "stringarraylist.h"
38
39 #ifdef FEATURE_COMINTEROP
40 #include "clrtocomcall.h"
41 #include "comtoclrcall.h"
42 #include "winrttypenameconverter.h"
43 #endif // FEATURE_COMINTEROP
44
45 #include "dllimportcallback.h"
46 #include "caparser.h"
47 #include "sigbuilder.h"
48 #include "cgensys.h"
49 #include "peimagelayout.inl"
50
51 #if defined(FEATURE_APPX_BINDER)
52 #include "appxutil.h"
53 #include "clrprivbinderappx.h"
54 #include "clrprivtypecachewinrt.h"
55 #endif // defined(FEATURE_APPX_BINDER)
56
57 #ifdef FEATURE_COMINTEROP
58 #include "clrprivbinderwinrt.h"
59 #include "winrthelpers.h"
60 #endif
61
62 #ifdef CROSSGEN_COMPILE
63 #include "crossgenroresolvenamespace.h"
64 #endif
65
66 #ifndef NO_NGENPDB
67 #include <cvinfo.h>
68 #endif
69
70 #ifdef FEATURE_PERFMAP
71 #include "perfmap.h"
72 #endif
73
74 #include "argdestination.h"
75
76 #include "versionresilienthashcode.h"
77
78 #ifdef CROSSGEN_COMPILE
79 CompilationDomain * theDomain;
80 #endif
81
82 VerboseLevel g_CorCompileVerboseLevel = CORCOMPILE_NO_LOG;
83
84 //
85 // CEECompileInfo implements most of ICorCompileInfo
86 //
87
88 HRESULT CEECompileInfo::Startup(  BOOL fForceDebug,
89                                   BOOL fForceProfiling,
90                                   BOOL fForceInstrument)
91 {
92     SystemDomain::SetCompilationOverrides(fForceDebug,
93                                           fForceProfiling,
94                                           fForceInstrument);
95
96     HRESULT hr = S_OK;
97
98     m_fCachingOfInliningHintsEnabled = TRUE;
99     m_fGeneratingNgenPDB = FALSE;
100
101     _ASSERTE(!g_fEEStarted && !g_fEEInit && "You cannot run the EE inside an NGEN compilation process");
102
103     if (!g_fEEStarted && !g_fEEInit)
104     {
105 #ifdef CROSSGEN_COMPILE
106         GetSystemInfo(&g_SystemInfo);
107
108         theDomain = new CompilationDomain(fForceDebug,
109                                           fForceProfiling,
110                                           fForceInstrument);
111 #endif
112
113         // When NGEN'ing this call may execute EE code, e.g. the managed code to set up
114         // the SharedDomain.
115         hr = InitializeEE(COINITEE_DEFAULT);
116     }
117
118     //
119     // JIT interface expects to be called with
120     // preemptive GC enabled
121     //
122     if (SUCCEEDED(hr)) {
123 #ifdef _DEBUG
124         Thread *pThread = GetThread();
125         _ASSERTE(pThread);
126 #endif
127
128         GCX_PREEMP_NO_DTOR();
129     }
130
131     return hr;
132 }
133
134 HRESULT CEECompileInfo::CreateDomain(ICorCompilationDomain **ppDomain,
135                                      IMetaDataAssemblyEmit *pEmitter,
136                                      BOOL fForceDebug,
137                                      BOOL fForceProfiling,
138                                      BOOL fForceInstrument,
139                                      BOOL fForceFulltrustDomain)
140 {
141     STANDARD_VM_CONTRACT;
142
143     COOPERATIVE_TRANSITION_BEGIN();
144
145 #ifndef CROSSGEN_COMPILE
146     AppDomainCreationHolder<CompilationDomain> pCompilationDomain;
147
148     pCompilationDomain.Assign(new CompilationDomain(fForceDebug,
149                                                     fForceProfiling,
150                                                     fForceInstrument));
151 #else
152     CompilationDomain * pCompilationDomain = theDomain;
153 #endif
154
155     {
156         SystemDomain::LockHolder lh;
157         pCompilationDomain->Init();
158     }
159
160     if (pEmitter)
161         pCompilationDomain->SetDependencyEmitter(pEmitter);
162     
163 #if defined(FEATURE_APPX_BINDER)
164     if (AppX::IsAppXProcess())
165     {
166         HRESULT hr = S_OK;
167         ReleaseHolder<ICLRPrivBinder> pBinderInterface;
168         CLRPrivBinderAppX * pBinder = CLRPrivBinderAppX::GetOrCreateBinder();
169         
170         IfFailThrow(pBinder->QueryInterface(IID_ICLRPrivBinder, &pBinderInterface));
171         pCompilationDomain->SetLoadContextHostBinder(pBinderInterface);
172     }
173 #endif // defined(FEATURE_APPX_BINDER)
174
175 #ifdef DEBUGGING_SUPPORTED 
176     // Notify the debugger here, before the thread transitions into the
177     // AD to finish the setup, and before any assemblies are loaded into it.
178     SystemDomain::PublishAppDomainAndInformDebugger(pCompilationDomain);
179 #endif // DEBUGGING_SUPPORTED
180     
181     pCompilationDomain->LoadSystemAssemblies();
182     
183     pCompilationDomain->SetupSharedStatics();
184     
185     *ppDomain = static_cast<ICorCompilationDomain*>(pCompilationDomain);
186     
187     {
188         GCX_COOP();
189
190         ENTER_DOMAIN_PTR(pCompilationDomain,ADV_COMPILATION)
191         {
192             if (fForceFulltrustDomain)
193                 ((ApplicationSecurityDescriptor *)pCompilationDomain->GetSecurityDescriptor())->SetGrantedPermissionSet(NULL, NULL, 0xFFFFFFFF);
194
195 #ifndef CROSSGEN_COMPILE
196 #endif
197             pCompilationDomain->InitializeDomainContext(TRUE, NULL, NULL);
198
199 #ifndef CROSSGEN_COMPILE
200
201             if (!NingenEnabled())
202             {
203                 APPDOMAINREF adRef = (APPDOMAINREF)pCompilationDomain->GetExposedObject();
204                 GCPROTECT_BEGIN(adRef);
205                 MethodDescCallSite initializeSecurity(METHOD__APP_DOMAIN__INITIALIZE_DOMAIN_SECURITY);
206                 ARG_SLOT args[] =
207                 {
208                     ObjToArgSlot(adRef),
209                     ObjToArgSlot(NULL),
210                     ObjToArgSlot(NULL),
211                     ObjToArgSlot(NULL),
212                     static_cast<ARG_SLOT>(FALSE)
213                 };
214                 initializeSecurity.Call(args);
215                 GCPROTECT_END();
216             }
217 #endif
218
219             {
220                 GCX_PREEMP();
221
222                 // We load assemblies as domain-bound (However, they're compiled as domain neutral)
223 #ifdef FEATURE_LOADER_OPTIMIZATION
224 #ifdef FEATURE_FUSION
225                 if (NingenEnabled())
226                 {
227                     pCompilationDomain->SetSharePolicy(AppDomain::SHARE_POLICY_NEVER);
228                 }
229                 else
230                 {
231                     pCompilationDomain->SetupLoaderOptimization(AppDomain::SHARE_POLICY_NEVER);
232                 }
233 #else //FEATURE_FUSION
234                 pCompilationDomain->SetSharePolicy(AppDomain::SHARE_POLICY_NEVER);
235 #endif //FEATURE_FUSION
236 #endif // FEATURE_LOADER_OPTIMIZATION
237
238 #ifdef FEATURE_FUSION
239                 CorCompileConfigFlags flags = PEFile::GetNativeImageConfigFlags(pCompilationDomain->m_fForceDebug,
240                                                                                 pCompilationDomain->m_fForceProfiling,
241                                                                                 pCompilationDomain->m_fForceInstrument);
242
243                 FusionBind::SetApplicationContextDWORDProperty(GetAppDomain()->GetFusionContext(),
244                                                                ACTAG_ZAP_CONFIG_FLAGS, flags);
245 #endif //FEATURE_FUSION
246             }
247
248             pCompilationDomain->SetFriendlyName(W("Compilation Domain"));
249             if (!NingenEnabled())
250             {
251                 Security::SetDefaultAppDomainProperty(pCompilationDomain->GetSecurityDescriptor());
252                 pCompilationDomain->GetSecurityDescriptor()->FinishInitialization();
253             }
254             SystemDomain::System()->LoadDomain(pCompilationDomain);
255
256 #ifndef CROSSGEN_COMPILE
257             pCompilationDomain.DoneCreating();
258 #endif
259         }
260         END_DOMAIN_TRANSITION;
261     }
262
263     COOPERATIVE_TRANSITION_END();
264
265     return S_OK;
266 }
267
268
269 HRESULT CEECompileInfo::DestroyDomain(ICorCompilationDomain *pDomain)
270 {
271     STANDARD_VM_CONTRACT;
272
273 #ifndef CROSSGEN_COMPILE
274     COOPERATIVE_TRANSITION_BEGIN();
275
276     GCX_COOP();
277
278     CompilationDomain *pCompilationDomain = (CompilationDomain *) pDomain;
279
280     // DDB 175659: Make sure that canCallNeedsRestore() returns FALSE during compilation 
281     // domain shutdown.
282     pCompilationDomain->setCannotCallNeedsRestore();
283
284     pCompilationDomain->Unload(TRUE);
285
286     COOPERATIVE_TRANSITION_END();
287 #endif
288
289     return S_OK;
290 }
291
292 HRESULT MakeCrossDomainCallbackWorker(
293     CROSS_DOMAIN_CALLBACK   pfnCallback,
294     LPVOID                  pArgs)
295 {
296     STATIC_CONTRACT_MODE_COOPERATIVE;
297     STATIC_CONTRACT_SO_INTOLERANT;
298
299     HRESULT hrRetVal = E_UNEXPECTED;
300     BEGIN_SO_TOLERANT_CODE(GetThread());
301     hrRetVal = pfnCallback(pArgs);
302     END_SO_TOLERANT_CODE;
303     return hrRetVal;
304 }
305
306 HRESULT CEECompileInfo::MakeCrossDomainCallback(
307     ICorCompilationDomain*  pDomain,
308     CROSS_DOMAIN_CALLBACK   pfnCallback,
309     LPVOID                  pArgs)
310 {
311     STANDARD_VM_CONTRACT;
312
313     HRESULT hrRetVal = E_UNEXPECTED;
314
315     COOPERATIVE_TRANSITION_BEGIN();
316
317     {
318         // Switch to cooperative mode to switch appdomains
319         GCX_COOP();
320
321         ENTER_DOMAIN_PTR((CompilationDomain*)pDomain,ADV_COMPILATION)
322         {
323             //
324             // Switch to preemptive mode on before calling back into
325             // the zapper
326             //
327             
328             GCX_PREEMP();
329             
330             hrRetVal = MakeCrossDomainCallbackWorker(pfnCallback, pArgs);
331         }
332         END_DOMAIN_TRANSITION;
333     }
334
335     COOPERATIVE_TRANSITION_END();
336
337     return hrRetVal;
338 }
339
340 #ifdef TRITON_STRESS_NEED_IMPL
341 int LogToSvcLogger(LPCWSTR format, ...)
342 {
343     STANDARD_VM_CONTRACT;
344
345     StackSString s;
346
347     va_list args;
348     va_start(args, format);
349     s.VPrintf(format, args);
350     va_end(args);
351
352     GetSvcLogger()->Printf(W("%s"), s.GetUnicode());
353
354     return 0;
355 }
356 #endif
357
358 HRESULT CEECompileInfo::LoadAssemblyByPath(
359     LPCWSTR                  wzPath,
360     
361     // Normally this is FALSE, but crossgen /CreatePDB sets this to TRUE, so it can
362     // explicitly load an NI by path
363     BOOL                     fExplicitBindToNativeImage,
364
365     CORINFO_ASSEMBLY_HANDLE *pHandle)
366 {
367     STANDARD_VM_CONTRACT;
368
369     HRESULT hr = S_OK;
370
371     COOPERATIVE_TRANSITION_BEGIN();
372
373     Assembly * pAssembly;
374     HRESULT    hrProcessLibraryBitnessMismatch = S_OK;
375
376     // We don't want to do a LoadFrom, since they do not work with ngen. Instead,
377     // read the metadata from the file and do a bind based on that.
378
379     EX_TRY
380     {
381         // Pre-open the image so we can grab some metadata to help initialize the
382         // binder's AssemblySpec, which we'll use later to load the assembly for real.
383
384         PEImageHolder pImage;
385
386
387         if (pImage == NULL)
388         {
389             pImage = PEImage::OpenImage(
390                 wzPath,
391
392                 // If we're explicitly binding to an NGEN image, we do not want the cache
393                 // this PEImage for use later, as pointers that need fixup (e.g.,
394                 // Module::m_pModuleSecurityDescriptor) will not be valid for use later. 
395                 // Normal caching is done when we open it "for real" further down when we
396                 // call LoadDomainAssembly().
397                 fExplicitBindToNativeImage ? MDInternalImport_NoCache : MDInternalImport_Default);
398         }
399
400         if (fExplicitBindToNativeImage && !pImage->HasReadyToRunHeader())
401         {
402             pImage->VerifyIsNIAssembly();
403         }
404         else
405         {
406             pImage->VerifyIsAssembly();
407         }
408
409         // Check to make sure the bitness of the assembly matches the bitness of the process
410         // we will be loading it into and store the result.  If a COR_IMAGE_ERROR gets thrown
411         // by LoadAssembly then we can blame it on bitness mismatch.  We do the check here
412         // and not in the CATCH to distinguish between the COR_IMAGE_ERROR that can be thrown by
413         // VerifyIsAssembly (not necessarily a bitness mismatch) and that from LoadAssembly
414 #ifdef _WIN64
415         if (pImage->Has32BitNTHeaders())
416         {
417             hrProcessLibraryBitnessMismatch = PEFMT_E_32BIT;
418         }
419 #else
420         if (!pImage->Has32BitNTHeaders())
421         {
422             hrProcessLibraryBitnessMismatch = PEFMT_E_64BIT;
423         }
424 #endif
425         
426         AssemblySpec spec;
427         spec.InitializeSpec(TokenFromRid(1, mdtAssembly), pImage->GetMDImport(), NULL, FALSE);
428
429         if (spec.IsMscorlib())
430         {
431             pAssembly = SystemDomain::System()->SystemAssembly();
432         }
433         else
434         {
435             AppDomain * pDomain = AppDomain::GetCurrentDomain();
436
437             PEAssemblyHolder pAssemblyHolder;
438             BOOL isWinRT = FALSE;
439
440 #ifdef FEATURE_COMINTEROP
441             isWinRT = spec.IsContentType_WindowsRuntime();
442             if (isWinRT)
443             {
444                 LPCSTR  szNameSpace;
445                 LPCSTR  szTypeName;
446                 // It does not make sense to pass the file name to recieve fake type name for empty WinMDs, because we would use the name 
447                 // for binding in next call to BindAssemblySpec which would fail for fake WinRT type name
448                 // We will throw/return the error instead and the caller will recognize it and react to it by not creating the ngen image - 
449                 // see code:Zapper::ComputeDependenciesInCurrentDomain
450                 IfFailThrow(::GetFirstWinRTTypeDef(pImage->GetMDImport(), &szNameSpace, &szTypeName, NULL, NULL));
451                 spec.SetWindowsRuntimeType(szNameSpace, szTypeName);
452             }
453 #endif //FEATURE_COMINTEROP
454
455             // If there is a host binder then use it to bind the assembly.
456             if (pDomain->HasLoadContextHostBinder() || isWinRT)
457             {
458                 pAssemblyHolder = pDomain->BindAssemblySpec(&spec, TRUE, FALSE);
459             }
460             else
461             {
462 #ifdef FEATURE_FUSION
463                 SafeComHolder<IBindResult> pNativeFusionAssembly;        
464                 SafeComHolder<IFusionBindLog> pFusionLog;
465                 SafeComHolder<IAssembly> pFusionAssembly;
466
467                 IfFailThrow(ExplicitBind(wzPath, pDomain->GetFusionContext(), EXPLICITBIND_FLAGS_EXE,
468                                          NULL, &pFusionAssembly, &pNativeFusionAssembly, &pFusionLog));
469
470                 pAssemblyHolder = PEAssembly::Open(pFusionAssembly, pNativeFusionAssembly, pFusionLog, FALSE, FALSE);
471 #else //FEATURE_FUSION
472                 //ExplicitBind
473                 CoreBindResult bindResult;
474                 spec.SetCodeBase(pImage->GetPath());
475                 spec.Bind(
476                     pDomain,
477                     TRUE,                   // fThrowOnFileNotFound
478                     &bindResult, 
479
480                     // fNgenExplicitBind: Generally during NGEN compilation, this is
481                     // TRUE, meaning "I am NGEN, and I am doing an explicit bind to the IL
482                     // image, so don't infer the NI and try to open it, because I already
483                     // have it open". But if we're executing crossgen /CreatePDB, this should
484                     // be FALSE so that downstream code doesn't assume we're explicitly
485                     // trying to bind to an IL image (we're actually explicitly trying to
486                     // open an NI).
487                     !fExplicitBindToNativeImage,
488
489                     // fExplicitBindToNativeImage: Most callers want this FALSE; but crossgen
490                     // /CreatePDB explicitly specifies NI names to open, and cannot assume
491                     // that IL assemblies will be available.
492                     fExplicitBindToNativeImage
493                     );
494                 pAssemblyHolder = PEAssembly::Open(&bindResult,FALSE,FALSE);
495 #endif //FEATURE_FUSION
496             }
497
498             // Now load assembly into domain.
499             DomainAssembly * pDomainAssembly = pDomain->LoadDomainAssembly(&spec, pAssemblyHolder, FILE_LOAD_BEGIN);
500
501 #ifndef FEATURE_APPX_BINDER
502             if (spec.CanUseWithBindingCache() && pDomainAssembly->CanUseWithBindingCache())
503                 pDomain->AddAssemblyToCache(&spec, pDomainAssembly);
504 #endif
505
506
507             {
508                 // Mark the assembly before it gets fully loaded and NGen image dependencies are verified. This is necessary
509                 // to allow skipping compilation if there is NGen image already.
510                 pDomainAssembly->GetFile()->SetSafeToHardBindTo();
511             }
512
513             pAssembly = pDomain->LoadAssembly(&spec, pAssemblyHolder, FILE_LOADED);
514
515             // Add a dependency to the current assembly.  This is done to match the behavior
516             // of LoadAssemblyFusion, so that the same native image is generated whether we
517             // ngen install by file name or by assembly name.
518             pDomain->ToCompilationDomain()->AddDependency(&spec, pAssemblyHolder);
519         }
520
521         // Kind of a workaround - if we could have loaded this assembly via normal load,
522
523         *pHandle = CORINFO_ASSEMBLY_HANDLE(pAssembly);
524     }
525     EX_CATCH_HRESULT(hr);
526     
527     if ( hrProcessLibraryBitnessMismatch != S_OK && ( hr == COR_E_BADIMAGEFORMAT || hr == HRESULT_FROM_WIN32(ERROR_BAD_EXE_FORMAT) ) )
528     {
529         hr = hrProcessLibraryBitnessMismatch;
530     }
531     
532     COOPERATIVE_TRANSITION_END();
533
534     return hr;
535 }
536
537 #ifdef FEATURE_FUSION
538
539 // Simple helper that factors out code common to LoadAssemblyByIAssemblyName and
540 // LoadAssemblyByName
541 static HRESULT LoadAssemblyByIAssemblyNameWorker(
542     IAssemblyName *pAssemblyName,
543     CORINFO_ASSEMBLY_HANDLE *pHandle)
544 {
545     CONTRACTL                   
546     {                           
547         THROWS;
548         GC_TRIGGERS;
549         MODE_ANY;
550         SO_INTOLERANT;
551         INJECT_FAULT(COMPlusThrowOM(););
552     }
553     CONTRACTL_END;              
554
555     Assembly *pAssembly;
556
557     AssemblySpec spec;
558     spec.InitializeSpec(pAssemblyName, NULL, FALSE);
559
560     if (spec.IsMscorlib())
561     {
562         pAssembly = SystemDomain::System()->SystemAssembly();
563     }
564     else
565     {
566
567         DomainAssembly * pDomainAssembly = spec.LoadDomainAssembly(FILE_LOAD_BEGIN);
568
569         // Mark the assembly before it gets fully loaded and NGen image dependencies are verified. This is necessary
570         // to allow skipping compilation if there is NGen image already.
571         pDomainAssembly->GetFile()->SetSafeToHardBindTo();
572
573         pAssembly = spec.LoadAssembly(FILE_LOADED);
574     }
575
576     //
577     // Return the module handle
578     //
579
580     *pHandle = CORINFO_ASSEMBLY_HANDLE(pAssembly);
581
582     return S_OK;
583 }
584
585 HRESULT CEECompileInfo::LoadAssemblyByName(
586     LPCWSTR                  wzName,
587     CORINFO_ASSEMBLY_HANDLE *pHandle)
588 {
589     STANDARD_VM_CONTRACT;
590
591     HRESULT hr = S_OK;
592
593     COOPERATIVE_TRANSITION_BEGIN();
594
595     EX_TRY
596     {
597         ReleaseHolder<IAssemblyName> pAssemblyName;
598         IfFailThrow(CreateAssemblyNameObject(&pAssemblyName, wzName, CANOF_PARSE_DISPLAY_NAME, NULL));
599         IfFailThrow(LoadAssemblyByIAssemblyNameWorker(pAssemblyName, pHandle));
600     }
601     EX_CATCH_HRESULT(hr);
602
603     COOPERATIVE_TRANSITION_END();
604
605     return hr;
606 }
607
608 HRESULT CEECompileInfo::LoadAssemblyRef(
609     IMDInternalImport       *pAssemblyImport,
610     mdAssemblyRef           ref,
611     CORINFO_ASSEMBLY_HANDLE *pHandle,
612     IAssemblyName           **refAssemblyName /*=NULL*/)
613 {
614     STANDARD_VM_CONTRACT;
615
616     HRESULT hr = S_OK;
617
618     ReleaseHolder<IAssemblyName> pAssemblyName;
619
620     COOPERATIVE_TRANSITION_BEGIN();
621     
622     EX_TRY
623     {
624         Assembly *pAssembly;
625
626         if (refAssemblyName)
627             *refAssemblyName = NULL;
628
629         AssemblySpec spec;
630         spec.InitializeSpec(ref, pAssemblyImport, NULL, FALSE);
631         
632         if (spec.HasBindableIdentity())
633         {
634             if (refAssemblyName)
635             {
636                 IfFailThrow(spec.CreateFusionName(&pAssemblyName));
637             }
638
639             pAssembly = spec.LoadAssembly(FILE_LOADED);
640
641             //
642             // Return the module handle
643             //
644
645             *pHandle = CORINFO_ASSEMBLY_HANDLE(pAssembly);
646         }
647         else
648         {   // Cannot load assembly refs with non-unique id.
649             hr = S_FALSE;
650         }
651     }
652     EX_CATCH_HRESULT(hr);
653
654     COOPERATIVE_TRANSITION_END();
655
656     if (refAssemblyName != NULL && pAssemblyName != NULL)
657     {
658         *refAssemblyName = pAssemblyName.Extract();
659     }
660
661     return hr;
662 }
663
664 HRESULT CEECompileInfo::LoadAssemblyByIAssemblyName(
665         IAssemblyName           *pAssemblyName,
666         CORINFO_ASSEMBLY_HANDLE *pHandle
667         )
668 {
669     STANDARD_VM_CONTRACT;
670
671     HRESULT hr = S_OK;
672
673     COOPERATIVE_TRANSITION_BEGIN();
674
675     EX_TRY
676     {
677         IfFailThrow(LoadAssemblyByIAssemblyNameWorker(pAssemblyName, pHandle));
678     }
679     EX_CATCH_HRESULT(hr);
680
681     COOPERATIVE_TRANSITION_END();
682
683     return hr;
684 }
685
686 #endif //FEATURE_FUSION
687
688 #ifdef FEATURE_COMINTEROP
689 HRESULT CEECompileInfo::LoadTypeRefWinRT(
690     IMDInternalImport       *pAssemblyImport,
691     mdTypeRef               ref,
692     CORINFO_ASSEMBLY_HANDLE *pHandle)
693 {
694     STANDARD_VM_CONTRACT;
695
696     HRESULT hr = S_OK;
697
698     ReleaseHolder<IAssemblyName> pAssemblyName;
699
700     COOPERATIVE_TRANSITION_BEGIN();
701     
702     EX_TRY
703     {
704         Assembly *pAssembly;
705
706         mdToken tkResolutionScope;
707         if(FAILED(pAssemblyImport->GetResolutionScopeOfTypeRef(ref, &tkResolutionScope)))
708             hr = S_FALSE;
709         else if(TypeFromToken(tkResolutionScope) == mdtAssemblyRef)
710         {
711             DWORD dwAssemblyRefFlags;
712             IfFailThrow(pAssemblyImport->GetAssemblyRefProps(tkResolutionScope, NULL, NULL,
713                                                      NULL, NULL,
714                                                      NULL, NULL, &dwAssemblyRefFlags));
715             if (IsAfContentType_WindowsRuntime(dwAssemblyRefFlags))
716             {
717                 LPCSTR psznamespace;
718                 LPCSTR pszname;
719                 pAssemblyImport->GetNameOfTypeRef(ref, &psznamespace, &pszname);
720                 AssemblySpec spec;
721                 spec.InitializeSpec(tkResolutionScope, pAssemblyImport, NULL, FALSE);
722                 spec.SetWindowsRuntimeType(psznamespace, pszname);
723                 
724                 _ASSERTE(spec.HasBindableIdentity());
725                 
726                 pAssembly = spec.LoadAssembly(FILE_LOADED);
727
728                 //
729                 // Return the module handle
730                 //
731
732                 *pHandle = CORINFO_ASSEMBLY_HANDLE(pAssembly);
733             }
734             else
735             {
736                 hr = S_FALSE;
737             }
738         }
739         else
740         {
741             hr = S_FALSE;
742         }
743     }
744     EX_CATCH_HRESULT(hr);
745
746     COOPERATIVE_TRANSITION_END();
747
748     return hr;
749 }
750 #endif
751
752 BOOL CEECompileInfo::IsInCurrentVersionBubble(CORINFO_MODULE_HANDLE hModule)
753 {
754     WRAPPER_NO_CONTRACT;
755
756     return ((Module*)hModule)->IsInCurrentVersionBubble();
757 }
758
759 HRESULT CEECompileInfo::LoadAssemblyModule(
760     CORINFO_ASSEMBLY_HANDLE assembly,
761     mdFile                  file,
762     CORINFO_MODULE_HANDLE   *pHandle)
763 {
764     STANDARD_VM_CONTRACT;
765
766     COOPERATIVE_TRANSITION_BEGIN();
767
768     Assembly *pAssembly = (Assembly*) assembly;
769
770     Module *pModule = pAssembly->GetManifestModule()->LoadModule(GetAppDomain(), file, TRUE)->GetModule();
771
772     //
773     // Return the module handle
774     //
775
776     *pHandle = CORINFO_MODULE_HANDLE(pModule);
777
778     COOPERATIVE_TRANSITION_END();
779
780     return S_OK;
781 }
782
783
784 BOOL CEECompileInfo::CheckAssemblyZap(
785     CORINFO_ASSEMBLY_HANDLE assembly, 
786   __out_ecount_opt(*cAssemblyManifestModulePath) 
787     LPWSTR                  assemblyManifestModulePath, 
788     LPDWORD                 cAssemblyManifestModulePath)
789 {
790     STANDARD_VM_CONTRACT;
791
792     BOOL result = FALSE;
793
794     COOPERATIVE_TRANSITION_BEGIN();
795
796     Assembly *pAssembly = (Assembly*) assembly;
797
798     if (pAssembly->GetManifestFile()->HasNativeImage())
799     {
800         PEImage *pImage = pAssembly->GetManifestFile()->GetPersistentNativeImage();
801
802         if (assemblyManifestModulePath != NULL)
803         {
804             DWORD length = pImage->GetPath().GetCount();
805             if (length > *cAssemblyManifestModulePath)
806             {
807                 length = *cAssemblyManifestModulePath - 1;
808                 wcsncpy_s(assemblyManifestModulePath, *cAssemblyManifestModulePath, pImage->GetPath(), length);
809                 assemblyManifestModulePath[length] = 0;
810             }
811             else
812                 wcscpy_s(assemblyManifestModulePath, *cAssemblyManifestModulePath, pImage->GetPath());
813         }
814
815         result = TRUE;
816     }
817
818     COOPERATIVE_TRANSITION_END();
819
820     return result;
821 }
822
823 HRESULT CEECompileInfo::SetCompilationTarget(CORINFO_ASSEMBLY_HANDLE     assembly,
824                                              CORINFO_MODULE_HANDLE       module)
825 {
826     STANDARD_VM_CONTRACT;
827
828     Assembly *pAssembly = (Assembly *) assembly;
829     Module *pModule = (Module *) module;
830
831     CompilationDomain *pDomain = (CompilationDomain *) GetAppDomain();
832     pDomain->SetTarget(pAssembly, pModule);
833
834     if (!pAssembly->IsSystem())
835     {
836         // It is possible to get through a compile without calling BindAssemblySpec on mscorlib.  This
837         // is because refs to mscorlib are short circuited in a number of places.  So, we will explicitly
838         // add it to our dependencies.
839
840         AssemblySpec mscorlib;
841         mscorlib.InitializeSpec(SystemDomain::SystemFile());
842         GetAppDomain()->BindAssemblySpec(&mscorlib,TRUE,FALSE);
843
844         if (!IsReadyToRunCompilation() && !SystemDomain::SystemFile()->HasNativeImage())
845         {
846             if (!CLRConfig::GetConfigValue(CLRConfig::INTERNAL_NgenAllowMscorlibSoftbind))
847             {
848                 return NGEN_E_SYS_ASM_NI_MISSING;
849             }
850         }
851     }
852
853 #ifdef FEATURE_READYTORUN_COMPILER
854     if (IsReadyToRunCompilation() && !pModule->IsILOnly())
855     {
856         GetSvcLogger()->Printf(LogLevel_Error, W("Error: /readytorun not supported for mixed mode assemblies\n"));
857         return E_FAIL;
858     }
859 #endif
860
861 #ifdef FEATURE_READYTORUN_COMPILER
862     if (IsReadyToRunCompilation() && !pModule->IsILOnly())
863     {
864         GetSvcLogger()->Printf(LogLevel_Error, W("Error: /readytorun not supported for mixed mode assemblies\n"));
865         return E_FAIL;
866     }
867 #endif
868
869     return S_OK;
870 }
871
872 IMDInternalImport *
873     CEECompileInfo::GetAssemblyMetaDataImport(CORINFO_ASSEMBLY_HANDLE assembly)
874 {
875     STANDARD_VM_CONTRACT;
876
877     IMDInternalImport * import;
878
879     COOPERATIVE_TRANSITION_BEGIN();
880
881     import = ((Assembly*)assembly)->GetManifestImport();
882     import->AddRef();
883
884     COOPERATIVE_TRANSITION_END();
885
886     return import;
887 }
888
889 IMDInternalImport *
890     CEECompileInfo::GetModuleMetaDataImport(CORINFO_MODULE_HANDLE scope)
891 {
892     STANDARD_VM_CONTRACT;
893
894     IMDInternalImport * import;
895
896     COOPERATIVE_TRANSITION_BEGIN();
897
898     import = ((Module*)scope)->GetMDImport();
899     import->AddRef();
900
901     COOPERATIVE_TRANSITION_END();
902
903     return import;
904 }
905
906 CORINFO_MODULE_HANDLE
907     CEECompileInfo::GetAssemblyModule(CORINFO_ASSEMBLY_HANDLE assembly)
908 {
909     STANDARD_VM_CONTRACT;
910
911     CANNOTTHROWCOMPLUSEXCEPTION();
912
913     return (CORINFO_MODULE_HANDLE) ((Assembly*)assembly)->GetManifestModule();
914 }
915
916 PEDecoder * CEECompileInfo::GetModuleDecoder(CORINFO_MODULE_HANDLE scope)
917 {
918     STANDARD_VM_CONTRACT;
919
920     PEDecoder *result;
921
922     COOPERATIVE_TRANSITION_BEGIN();
923
924     //
925     // Note that we go ahead and return the native image if we are using that.
926     // It contains everything we need to ngen.  However, the caller must be
927     // aware and check for the native image case, since some fields will need to come
928     // from the CORCOMPILE_ZAP_HEADER rather than the PE headers.
929     //
930
931     PEFile *pFile = ((Module *) scope)->GetFile();
932
933     if (pFile->HasNativeImage())
934         result = pFile->GetLoadedNative();
935     else
936         result = pFile->GetLoadedIL();
937
938     COOPERATIVE_TRANSITION_END();
939
940     return result;
941
942 }
943
944 void CEECompileInfo::GetModuleFileName(CORINFO_MODULE_HANDLE scope,
945                                        SString               &result)
946 {
947     STANDARD_VM_CONTRACT;
948
949     COOPERATIVE_TRANSITION_BEGIN();
950
951     result.Set(((Module*)scope)->GetPath());
952
953     COOPERATIVE_TRANSITION_END();
954 }
955
956 CORINFO_ASSEMBLY_HANDLE
957     CEECompileInfo::GetModuleAssembly(CORINFO_MODULE_HANDLE module)
958 {
959     STANDARD_VM_CONTRACT;
960
961     CANNOTTHROWCOMPLUSEXCEPTION();
962
963     return (CORINFO_ASSEMBLY_HANDLE) GetModule(module)->GetAssembly();
964 }
965
966 #ifdef FEATURE_FUSION
967 HRESULT CEECompileInfo::GetAssemblyName(
968     CORINFO_ASSEMBLY_HANDLE hAssembly,
969     DWORD                   dwFlags,
970     __out_z LPWSTR          wzAssemblyName, 
971     LPDWORD                 pcchAssemblyName)
972 {
973     STANDARD_VM_CONTRACT;
974
975     _ASSERTE(hAssembly != NULL);
976     if (hAssembly == NULL)
977     {
978         return E_INVALIDARG;
979     }
980
981     HRESULT hr = S_OK;
982     EX_TRY
983     {
984         Assembly *pAssembly = (Assembly *) hAssembly;
985         IAssemblyName * pAssemblyName = pAssembly->GetFusionAssemblyName();
986         if (dwFlags == GANF_Default)
987         {
988             hr = pAssemblyName->GetDisplayName(wzAssemblyName, pcchAssemblyName, 0);
989         }
990         else if (dwFlags == GANF_Simple)
991         {
992             DWORD cbAssemblyName = *pcchAssemblyName * sizeof(WCHAR);
993             hr = pAssemblyName->GetProperty(ASM_NAME_NAME, (LPVOID)wzAssemblyName, &cbAssemblyName);
994             *pcchAssemblyName = cbAssemblyName / sizeof(WCHAR);
995         }
996     }
997     EX_CATCH_HRESULT(hr);
998
999     return hr;
1000 }
1001 #endif //FEATURE_FUSION
1002
1003 #ifdef CROSSGEN_COMPILE
1004 //
1005 // Small wrapper to avoid having too many crossgen ifdefs
1006 //
1007 class AssemblyForLoadHint
1008 {
1009     IMDInternalImport * m_pMDImport;
1010 public:
1011     AssemblyForLoadHint(IMDInternalImport * pMDImport)
1012         : m_pMDImport(pMDImport)
1013     {
1014     }
1015
1016     IMDInternalImport * GetManifestImport()
1017     {
1018         return m_pMDImport;
1019     }
1020
1021     LPCSTR GetSimpleName()
1022     {
1023         LPCSTR name = "";
1024         IfFailThrow(m_pMDImport->GetAssemblyProps(TokenFromRid(1, mdtAssembly), NULL, NULL, NULL, &name, NULL, NULL));
1025         return name;
1026     }
1027
1028     void GetDisplayName(SString &result, DWORD flags = 0)
1029     {
1030         PEAssembly::GetFullyQualifiedAssemblyName(m_pMDImport, TokenFromRid(1, mdtAssembly), result, flags);
1031     }
1032
1033     BOOL IsSystem()
1034     {
1035         return FALSE;
1036     }
1037 };
1038 #endif
1039
1040 //-----------------------------------------------------------------------------
1041 // For an assembly with a full name of "Foo, Version=2.0.0.0, Culture=neutral",
1042 // we want any of these attributes specifications to match:
1043 //    DependencyAttribute("Foo", LoadHint.Always)
1044 //    DependencyAttribute("Foo,", LoadHint.Always)
1045 //    DependencyAttribute("Foo, Version=2.0.0.0, Culture=neutral", LoadHint.Always)
1046 // The second case of "Foo," is needed only for intra-V2 compat as
1047 // it was supported at one point during V2. We may be able to get rid of it.
1048 template <typename ASSEMBLY>
1049 BOOL IsAssemblySpecifiedInCA(ASSEMBLY * pAssembly, SString dependencyNameFromCA)
1050 {
1051     STANDARD_VM_CONTRACT;
1052
1053     // First, check for this:
1054     //    DependencyAttribute("Foo", LoadHint.Always)
1055     StackSString simpleName(SString::Utf8, pAssembly->GetSimpleName());
1056     if (simpleName.EqualsCaseInsensitive(dependencyNameFromCA, PEImage::GetFileSystemLocale()))
1057         return TRUE;
1058
1059     // Now, check for this:
1060     //    DependencyAttribute("Foo,", LoadHint.Always)
1061     SString comma(W(","));
1062     StackSString simpleNameWithComma(simpleName, comma);
1063     if (simpleNameWithComma.EqualsCaseInsensitive(dependencyNameFromCA, PEImage::GetFileSystemLocale()))
1064         return TRUE;
1065
1066     // Finally:
1067     //    DependencyAttribute("Foo, Version=2.0.0.0, Culture=neutral", LoadHint.Always)
1068     StackSString fullName;
1069     pAssembly->GetDisplayName(fullName);
1070     if (fullName.EqualsCaseInsensitive(dependencyNameFromCA))
1071         return TRUE;
1072
1073     return FALSE;
1074 }
1075
1076 template <typename ASSEMBLY>
1077 void GetLoadHint(ASSEMBLY * pAssembly, ASSEMBLY *pAssemblyDependency,
1078                  LoadHintEnum *loadHint, LoadHintEnum *defaultLoadHint = NULL)
1079 {
1080     STANDARD_VM_CONTRACT;
1081
1082     *loadHint = LoadDefault;
1083
1084     if (g_pConfig->NgenHardBind() == EEConfig::NGEN_HARD_BIND_ALL)
1085         *loadHint = LoadAlways;
1086
1087     const BYTE  *pbAttr;                // Custom attribute data as a BYTE*.
1088     ULONG       cbAttr;                 // Size of custom attribute data.
1089     mdToken     mdAssembly;
1090
1091     // Look for the binding custom attribute
1092     {
1093         IMDInternalImport *pImport = pAssembly->GetManifestImport();
1094
1095         IfFailThrow(pImport->GetAssemblyFromScope(&mdAssembly));
1096
1097         MDEnumHolder hEnum(pImport);        // Enumerator for custom attributes
1098         IfFailThrow(pImport->EnumCustomAttributeByNameInit(mdAssembly, DEPENDENCY_TYPE, &hEnum));
1099
1100         mdCustomAttribute tkAttribute;      // A custom attribute on this assembly.
1101         while (pImport->EnumNext(&hEnum, &tkAttribute))
1102         {
1103             // Get raw custom attribute.
1104             IfFailThrow(pImport->GetCustomAttributeAsBlob(tkAttribute, (const void**)&pbAttr, &cbAttr));
1105
1106             CustomAttributeParser cap(pbAttr, cbAttr);
1107
1108             IfFailThrow(cap.ValidateProlog());
1109
1110             // Extract string from custom attribute
1111             LPCUTF8 szString;
1112             ULONG   cbString;
1113             IfFailThrow(cap.GetNonNullString(&szString, &cbString));
1114
1115             // Convert the string to Unicode.
1116             StackSString dependencyNameFromCA(SString::Utf8, szString, cbString);
1117
1118             if (IsAssemblySpecifiedInCA(pAssemblyDependency, dependencyNameFromCA))
1119             {
1120                 // Get dependency setting
1121                 UINT32 u4;
1122                 IfFailThrow(cap.GetU4(&u4));
1123                 *loadHint = (LoadHintEnum)u4;
1124                 break;
1125             }
1126         }
1127     }
1128
1129     // If not preference is specified, look for the built-in assembly preference
1130     if (*loadHint == LoadDefault || defaultLoadHint != NULL)
1131     {
1132         IMDInternalImport *pImportDependency = pAssemblyDependency->GetManifestImport();
1133
1134         IfFailThrow(pImportDependency->GetAssemblyFromScope(&mdAssembly));
1135
1136         HRESULT hr = pImportDependency->GetCustomAttributeByName(mdAssembly,
1137             DEFAULTDEPENDENCY_TYPE,
1138             (const void**)&pbAttr, &cbAttr);
1139         IfFailThrow(hr);
1140
1141         // Parse the attribute
1142         if (hr == S_OK)
1143         {
1144             CustomAttributeParser cap(pbAttr, cbAttr);
1145             IfFailThrow(cap.ValidateProlog());
1146
1147             // Get default bind setting
1148             UINT32 u4 = 0;
1149             IfFailThrow(cap.GetU4(&u4));
1150
1151             if (pAssemblyDependency->IsSystem() && CLRConfig::GetConfigValue(CLRConfig::INTERNAL_NgenAllowMscorlibSoftbind))
1152             {
1153                 u4 = LoadDefault;
1154             }
1155
1156             if (defaultLoadHint)
1157                 *defaultLoadHint = (LoadHintEnum) u4;
1158             else
1159                 *loadHint = (LoadHintEnum) u4;
1160         }
1161     }
1162 }
1163
1164 HRESULT CEECompileInfo::GetLoadHint(CORINFO_ASSEMBLY_HANDLE hAssembly,
1165                                     CORINFO_ASSEMBLY_HANDLE hAssemblyDependency,
1166                                     LoadHintEnum *loadHint,
1167                                     LoadHintEnum *defaultLoadHint)
1168 {
1169     STANDARD_VM_CONTRACT;
1170
1171     HRESULT hr = S_OK;
1172
1173     EX_TRY
1174     {
1175         Assembly *pAssembly           = (Assembly *) hAssembly;
1176         Assembly *pAssemblyDependency = (Assembly *) hAssemblyDependency;
1177
1178         ::GetLoadHint(pAssembly, pAssemblyDependency, loadHint, defaultLoadHint);
1179     }
1180     EX_CATCH_HRESULT(hr);
1181
1182     return hr;
1183 }
1184
1185 HRESULT CEECompileInfo::GetAssemblyVersionInfo(CORINFO_ASSEMBLY_HANDLE hAssembly,
1186                                                CORCOMPILE_VERSION_INFO *pInfo)
1187 {
1188     STANDARD_VM_CONTRACT;
1189
1190     Assembly *pAssembly = (Assembly *) hAssembly;
1191
1192     pAssembly->GetDomainAssembly()->GetCurrentVersionInfo(pInfo);
1193
1194     return S_OK;
1195 }
1196
1197 void CEECompileInfo::GetAssemblyCodeBase(CORINFO_ASSEMBLY_HANDLE hAssembly, SString &result)
1198 {
1199     STANDARD_VM_CONTRACT;
1200
1201     COOPERATIVE_TRANSITION_BEGIN();
1202
1203     Assembly *pAssembly = (Assembly *)hAssembly;
1204     _ASSERTE(pAssembly != NULL);
1205
1206     pAssembly->GetCodeBase(result);
1207
1208     COOPERATIVE_TRANSITION_END();
1209 }
1210
1211 //=================================================================================
1212
1213 void FakePromote(PTR_PTR_Object ppObj, ScanContext *pSC, uint32_t dwFlags)
1214 {
1215     CONTRACTL {
1216         NOTHROW;
1217         GC_NOTRIGGER;
1218         MODE_ANY;
1219     } CONTRACTL_END;
1220
1221     _ASSERTE(*ppObj == NULL);
1222     *(CORCOMPILE_GCREFMAP_TOKENS *)ppObj = (dwFlags & GC_CALL_INTERIOR) ? GCREFMAP_INTERIOR : GCREFMAP_REF;
1223 }
1224
1225 //=================================================================================
1226
1227 void FakePromoteCarefully(promote_func *fn, Object **ppObj, ScanContext *pSC, uint32_t dwFlags)
1228 {
1229     (*fn)(ppObj, pSC, dwFlags);
1230 }
1231
1232 //=================================================================================
1233
1234 void FakeGcScanRoots(MetaSig& msig, ArgIterator& argit, MethodDesc * pMD, BYTE * pFrame)
1235 {
1236     STANDARD_VM_CONTRACT;
1237
1238     ScanContext sc;
1239
1240     // Encode generic instantiation arg
1241     if (argit.HasParamType())
1242     {
1243         // Note that intrinsic array methods have hidden instantiation arg too, but it is not reported to GC
1244         if (pMD->RequiresInstMethodDescArg())
1245             *(CORCOMPILE_GCREFMAP_TOKENS *)(pFrame + argit.GetParamTypeArgOffset()) = GCREFMAP_METHOD_PARAM;
1246         else 
1247         if (pMD->RequiresInstMethodTableArg())
1248             *(CORCOMPILE_GCREFMAP_TOKENS *)(pFrame + argit.GetParamTypeArgOffset()) = GCREFMAP_TYPE_PARAM;
1249     }
1250
1251     // If the function has a this pointer, add it to the mask
1252     if (argit.HasThis())
1253     {
1254         BOOL interior = pMD->GetMethodTable()->IsValueType() && !pMD->IsUnboxingStub();
1255
1256         FakePromote((Object **)(pFrame + argit.GetThisOffset()), &sc, interior ? GC_CALL_INTERIOR : 0);
1257     }
1258
1259     if (argit.IsVarArg())
1260     {
1261         *(CORCOMPILE_GCREFMAP_TOKENS *)(pFrame + argit.GetVASigCookieOffset()) = GCREFMAP_VASIG_COOKIE;
1262
1263         // We are done for varargs - the remaining arguments are reported via vasig cookie
1264         return;
1265     }
1266
1267     // Also if the method has a return buffer, then it is the first argument, and could be an interior ref,
1268     // so always promote it.
1269     if (argit.HasRetBuffArg())
1270     {
1271         FakePromote((Object **)(pFrame + argit.GetRetBuffArgOffset()), &sc, GC_CALL_INTERIOR);
1272     }
1273
1274     //
1275     // Now iterate the arguments
1276     //
1277
1278     // Cycle through the arguments, and call msig.GcScanRoots for each
1279     int argOffset;
1280     while ((argOffset = argit.GetNextOffset()) != TransitionBlock::InvalidOffset)
1281     {
1282         ArgDestination argDest(pFrame, argOffset, argit.GetArgLocDescForStructInRegs());
1283         msig.GcScanRoots(&argDest, &FakePromote, &sc, &FakePromoteCarefully);
1284     }
1285 }
1286
1287 void CEECompileInfo::GetCallRefMap(CORINFO_METHOD_HANDLE hMethod, GCRefMapBuilder * pBuilder)
1288 {
1289 #ifdef _DEBUG
1290     DWORD dwInitialLength = pBuilder->GetBlobLength();
1291     UINT nTokensWritten = 0;
1292 #endif
1293
1294     MethodDesc *pMD = (MethodDesc *)hMethod;
1295
1296     MetaSig msig(pMD);
1297     ArgIterator argit(&msig);
1298
1299     UINT nStackBytes = argit.SizeOfFrameArgumentArray();
1300
1301     // Allocate a fake stack
1302     CQuickBytes qbFakeStack;
1303     qbFakeStack.AllocThrows(sizeof(TransitionBlock) + nStackBytes);
1304     memset(qbFakeStack.Ptr(), 0, qbFakeStack.Size());
1305
1306     BYTE * pFrame = (BYTE *)qbFakeStack.Ptr();
1307
1308     // Fill it in
1309     FakeGcScanRoots(msig, argit, pMD, pFrame);
1310
1311     //
1312     // Encode the ref map
1313     //
1314
1315     UINT nStackSlots;
1316
1317 #ifdef _TARGET_X86_
1318     UINT cbStackPop = argit.CbStackPop();
1319     pBuilder->WriteStackPop(cbStackPop / sizeof(TADDR));
1320
1321     nStackSlots = nStackBytes / sizeof(TADDR) + NUM_ARGUMENT_REGISTERS;
1322 #else
1323     nStackSlots = (sizeof(TransitionBlock) + nStackBytes - TransitionBlock::GetOffsetOfArgumentRegisters()) / sizeof(TADDR);
1324 #endif
1325
1326     for (UINT pos = 0; pos < nStackSlots; pos++)
1327     {
1328         int ofs;
1329
1330 #ifdef _TARGET_X86_
1331         ofs = (pos < NUM_ARGUMENT_REGISTERS) ?
1332             (TransitionBlock::GetOffsetOfArgumentRegisters() + ARGUMENTREGISTERS_SIZE - (pos + 1) * sizeof(TADDR)) :
1333             (TransitionBlock::GetOffsetOfArgs() + (pos - NUM_ARGUMENT_REGISTERS) * sizeof(TADDR));
1334 #else
1335         ofs = TransitionBlock::GetOffsetOfArgumentRegisters() + pos * sizeof(TADDR);
1336 #endif
1337
1338         CORCOMPILE_GCREFMAP_TOKENS token = *(CORCOMPILE_GCREFMAP_TOKENS *)(pFrame + ofs);
1339
1340         if (token != 0)
1341         {
1342             INDEBUG(nTokensWritten++;)
1343             pBuilder->WriteToken(pos, token);
1344         }
1345     }
1346
1347     // We are done
1348     pBuilder->Flush();
1349
1350 #ifdef _DEBUG
1351     //
1352     // Verify that decoder produces what got encoded
1353     //
1354
1355     DWORD dwFinalLength;
1356     PVOID pBlob = pBuilder->GetBlob(&dwFinalLength);
1357
1358     UINT nTokensDecoded = 0;
1359
1360     GCRefMapDecoder decoder((BYTE *)pBlob + dwInitialLength);
1361
1362 #ifdef _TARGET_X86_
1363     _ASSERTE(decoder.ReadStackPop() * sizeof(TADDR) == cbStackPop);
1364 #endif
1365
1366     while (!decoder.AtEnd())
1367     {
1368         int pos = decoder.CurrentPos();
1369         int token = decoder.ReadToken();
1370
1371         int ofs;
1372
1373 #ifdef _TARGET_X86_
1374         ofs = (pos < NUM_ARGUMENT_REGISTERS) ?
1375             (TransitionBlock::GetOffsetOfArgumentRegisters() + ARGUMENTREGISTERS_SIZE - (pos + 1) * sizeof(TADDR)) :
1376             (TransitionBlock::GetOffsetOfArgs() + (pos - NUM_ARGUMENT_REGISTERS) * sizeof(TADDR));
1377 #else
1378         ofs = TransitionBlock::GetOffsetOfArgumentRegisters() + pos * sizeof(TADDR);
1379 #endif
1380
1381         if (token != 0)
1382         {
1383             _ASSERTE(*(CORCOMPILE_GCREFMAP_TOKENS *)(pFrame + ofs) == token);
1384             nTokensDecoded++;
1385         }
1386     }
1387
1388     // Verify that all tokens got decoded.
1389     _ASSERTE(nTokensWritten == nTokensDecoded);
1390 #endif // _DEBUG
1391 }
1392
1393 void CEECompileInfo::CompressDebugInfo(
1394     IN ICorDebugInfo::OffsetMapping * pOffsetMapping,
1395     IN ULONG            iOffsetMapping,
1396     IN ICorDebugInfo::NativeVarInfo * pNativeVarInfo,
1397     IN ULONG            iNativeVarInfo,
1398     IN OUT SBuffer    * pDebugInfoBuffer
1399     )
1400 {
1401     STANDARD_VM_CONTRACT;
1402
1403     CompressDebugInfo::CompressBoundariesAndVars(pOffsetMapping, iOffsetMapping, pNativeVarInfo, iNativeVarInfo, pDebugInfoBuffer, NULL);
1404 }
1405
1406 HRESULT CEECompileInfo::GetBaseJitFlags(
1407         IN  CORINFO_METHOD_HANDLE   hMethod,
1408         OUT CORJIT_FLAGS           *pFlags)
1409 {
1410     STANDARD_VM_CONTRACT;
1411
1412     MethodDesc *pMD = (MethodDesc *)hMethod;
1413     *pFlags = CEEInfo::GetBaseCompileFlags(pMD);
1414
1415     return S_OK;
1416 }
1417
1418 //=================================================================================
1419
1420 #ifdef _DEBUG 
1421
1422 static struct
1423 {
1424     size_t total;
1425     size_t noEmbed;
1426     size_t array;
1427     size_t primitives;
1428     size_t szarray;
1429 } embedStats;
1430
1431 #endif // _DEBUG
1432
1433 BOOL CEEPreloader::CanEmbedClassID(CORINFO_CLASS_HANDLE    typeHandle)
1434 {
1435     STANDARD_VM_CONTRACT;
1436
1437     TypeHandle hnd = (TypeHandle) typeHandle;
1438     return m_image->CanEagerBindToTypeHandle(hnd) && 
1439         !hnd.AsMethodTable()->NeedsCrossModuleGenericsStaticsInfo();
1440 }
1441
1442 BOOL CEEPreloader::CanEmbedModuleID(CORINFO_MODULE_HANDLE    moduleHandle)
1443 {
1444     STANDARD_VM_CONTRACT;
1445
1446     return m_image->CanEagerBindToModule((Module *)moduleHandle);
1447 }
1448
1449 BOOL CEEPreloader::CanEmbedModuleHandle(CORINFO_MODULE_HANDLE    moduleHandle)
1450 {
1451     STANDARD_VM_CONTRACT;
1452
1453     return m_image->CanEagerBindToModule((Module *)moduleHandle);
1454
1455 }
1456 BOOL CEEPreloader::CanEmbedClassHandle(CORINFO_CLASS_HANDLE    typeHandle)
1457 {
1458     STANDARD_VM_CONTRACT;
1459
1460     TypeHandle hnd = (TypeHandle) typeHandle;
1461
1462     BOOL decision = m_image->CanEagerBindToTypeHandle(hnd);
1463
1464 #ifdef _DEBUG 
1465     embedStats.total++;
1466
1467     if (!decision)
1468         embedStats.noEmbed++;
1469
1470     if (hnd.IsArray())
1471     {
1472         embedStats.array++;
1473
1474         CorElementType arrType = hnd.AsArray()->GetInternalCorElementType();
1475         if (arrType == ELEMENT_TYPE_SZARRAY)
1476             embedStats.szarray++;
1477
1478         CorElementType elemType = hnd.AsArray()->GetArrayElementTypeHandle().GetInternalCorElementType();
1479         if (elemType <= ELEMENT_TYPE_R8)
1480             embedStats.primitives++;
1481     }
1482 #endif // _DEBUG
1483     return decision;
1484 }
1485
1486
1487 /*static*/ BOOL CanEmbedMethodDescViaContext(MethodDesc * pMethod, MethodDesc * pContext)
1488 {
1489     STANDARD_VM_CONTRACT;
1490
1491     if (pContext != NULL)
1492     {
1493         _ASSERTE(pContext->GetLoaderModule() == GetAppDomain()->ToCompilationDomain()->GetTargetModule());
1494
1495         // a method can always embed its own handle
1496         if (pContext == pMethod)
1497         {
1498             return TRUE;
1499         }
1500
1501         // Methods that are tightly bound to the same method table can 
1502         // always refer each other directly. This check allows methods 
1503         // within one speculative generic instantiations to call each 
1504         // other directly.
1505         //
1506         if ((pContext->GetMethodTable() == pMethod->GetMethodTable()) &&
1507             pContext->IsTightlyBoundToMethodTable() &&
1508             pMethod->IsTightlyBoundToMethodTable())
1509         {
1510             return TRUE;
1511         }
1512     }
1513     return FALSE;
1514 }
1515
1516 BOOL CEEPreloader::CanEmbedMethodHandle(CORINFO_METHOD_HANDLE methodHandle, 
1517                                         CORINFO_METHOD_HANDLE contextHandle)
1518 {
1519     STANDARD_VM_CONTRACT;
1520
1521     MethodDesc * pContext = GetMethod(contextHandle);
1522     MethodDesc * pMethod  = GetMethod(methodHandle);
1523
1524     if (CanEmbedMethodDescViaContext(pMethod, pContext))
1525         return TRUE;
1526
1527     return m_image->CanEagerBindToMethodDesc(pMethod);
1528 }
1529
1530 BOOL CEEPreloader::CanEmbedFieldHandle(CORINFO_FIELD_HANDLE    fieldHandle)
1531 {
1532     STANDARD_VM_CONTRACT;
1533
1534     return m_image->CanEagerBindToFieldDesc((FieldDesc *) fieldHandle);
1535
1536 }
1537
1538 void* CEECompileInfo::GetStubSize(void *pStubAddress, DWORD *pSizeToCopy)
1539 {
1540     CONTRACT(void*)
1541     {
1542         STANDARD_VM_CHECK;
1543         PRECONDITION(pStubAddress && pSizeToCopy);
1544     }
1545     CONTRACT_END;
1546
1547     Stub *stub = Stub::RecoverStubAndSize((TADDR)pStubAddress, pSizeToCopy);
1548     _ASSERTE(*pSizeToCopy > sizeof(Stub));
1549     RETURN stub;
1550 }
1551
1552 HRESULT CEECompileInfo::GetStubClone(void *pStub, BYTE *pBuffer, DWORD dwBufferSize)
1553 {
1554     STANDARD_VM_CONTRACT;
1555
1556     if (pStub == NULL)
1557     {
1558         return E_INVALIDARG;
1559     }
1560
1561     return (reinterpret_cast<Stub *>(pStub)->CloneStub(pBuffer, dwBufferSize));
1562 }
1563
1564 HRESULT CEECompileInfo::GetTypeDef(CORINFO_CLASS_HANDLE classHandle,
1565                                    mdTypeDef *token)
1566 {
1567     STANDARD_VM_CONTRACT;
1568
1569     CANNOTTHROWCOMPLUSEXCEPTION();
1570
1571     TypeHandle hClass(classHandle);
1572
1573     *token = hClass.GetCl();
1574
1575     return S_OK;
1576 }
1577
1578 HRESULT CEECompileInfo::GetMethodDef(CORINFO_METHOD_HANDLE methodHandle,
1579                                      mdMethodDef *token)
1580 {
1581     STANDARD_VM_CONTRACT;
1582
1583     CANNOTTHROWCOMPLUSEXCEPTION();
1584
1585     *token = ((MethodDesc*)methodHandle)->GetMemberDef();
1586
1587     return S_OK;
1588 }
1589
1590 /*********************************************************************/
1591 // Used to determine if a methodHandle can be embedded in an ngen image.
1592 // Depends on what things are persisted by CEEPreloader
1593
1594 BOOL CEEPreloader::CanEmbedFunctionEntryPoint(
1595     CORINFO_METHOD_HANDLE   methodHandle,
1596     CORINFO_METHOD_HANDLE   contextHandle, /* = NULL */
1597     CORINFO_ACCESS_FLAGS    accessFlags /*=CORINFO_ACCESS_ANY*/)
1598 {
1599     STANDARD_VM_CONTRACT;
1600
1601     MethodDesc * pMethod = GetMethod(methodHandle);
1602     MethodDesc * pContext = GetMethod(contextHandle);
1603
1604     // IsRemotingInterceptedViaVirtualDispatch is a rather special case.
1605     //
1606     // Other remoting intercepts are implemented by one of:
1607     //  (1) in DoPrestub (for non-virtual calls)
1608     //  (2) by transparent proxy vtables, where all the entries in the vtable
1609     //      go to the same code.
1610     //
1611     // However when calling virtual functions non-virtually the JIT interface
1612     // pointer to the code for the function in a stub 
1613     // (see GetNonVirtualEntryPointForVirtualMethod).  
1614     // Thus we cannot embed non-virtual calls to these functions because we 
1615     // don't save these stubs.  Unlike most other remoting stubs these ones 
1616     // are NOT inserted by DoPrestub.
1617     //
1618     if (((accessFlags & CORINFO_ACCESS_THIS) == 0) &&
1619         (pMethod->IsRemotingInterceptedViaVirtualDispatch()))
1620     {
1621         return FALSE;
1622     }
1623
1624     // Methods with native callable attribute are special , since 
1625     // they are used as LDFTN targets.Native Callable methods
1626     // uses the same code path as reverse pinvoke and embedding them
1627     // in an ngen image require saving the reverse pinvoke stubs.
1628     if (pMethod->HasNativeCallableAttribute())
1629         return FALSE;
1630
1631     return TRUE;
1632 }
1633
1634 BOOL CEEPreloader::DoesMethodNeedRestoringBeforePrestubIsRun(
1635         CORINFO_METHOD_HANDLE   methodHandle)
1636 {
1637     STANDARD_VM_CONTRACT;
1638
1639     MethodDesc * ftn = GetMethod(methodHandle);
1640
1641     // The restore mechanism for InstantiatedMethodDescs (IMDs) is complicated, and causes
1642     // circular dependency complications with the GC if we hardbind to the prestub/precode
1643     // of an unrestored IMD. As such, we're eliminating hardbinding to unrestored MethodDescs
1644     // that belong to generic types.
1645
1646     //@TODO: The reduction may be overkill, and we may consider refining the cases.
1647
1648     // Specifically, InstantiatedMethodDescs can have preferred zap modules different than
1649     // the zap modules for their owning types. As such, in a soft-binding case a MethodDesc
1650     // may not be able to trace back to its owning Module without hitting an unrestored
1651     // fixup token. For example, the 64-bit JIT can not yet provide generic type arguments
1652     // and uses instantiating stubs to call static methods on generic types. If such an stub
1653     // belong to a module other than the module in which the generic type is declared, then
1654     // it is possible for the MethodTable::m_pEEClass or the EEClass::m_pModule pointers to 
1655     // be unrestored. The complication arises when a call to the prestub/precode of such 
1656     // an unrestored IMD causes us try to restore the IMD and this in turn causes us to 
1657     // transition to preemptive GC and as such GC needs the metadata signature from the IMD 
1658     // to iterate its arguments. But since we're currently restoring the IMD, we may not be 
1659     // able to get to the signature, and as such we're stuck.
1660
1661     // The same problem exists for instantiation arguments. We may need the instantiation
1662     // arguments while walking the signature during GC, and if they are not restored we're stuck.
1663
1664     if (ftn->HasClassOrMethodInstantiation())
1665     {
1666         if (ftn->NeedsRestore(m_image))
1667             return TRUE;
1668     }
1669
1670     return FALSE;
1671 }
1672
1673 BOOL CEECompileInfo::IsNativeCallableMethod(CORINFO_METHOD_HANDLE handle)
1674 {
1675     WRAPPER_NO_CONTRACT;
1676
1677     MethodDesc * pMethod = GetMethod(handle);
1678     return pMethod->HasNativeCallableAttribute();
1679 }
1680
1681 BOOL CEEPreloader::CanSkipDependencyActivation(CORINFO_METHOD_HANDLE   context,
1682                                                CORINFO_MODULE_HANDLE   moduleFrom,
1683                                                CORINFO_MODULE_HANDLE   moduleTo)
1684 {
1685     STANDARD_VM_CONTRACT;
1686
1687     // Can't skip any fixups for speculative generic instantiations
1688     if (Module::GetPreferredZapModuleForMethodDesc(GetMethod(context)) != m_image->GetModule())
1689         return FALSE;
1690
1691     // We don't need a fixup for eager bound dependencies since we are going to have 
1692     // an uncontional one already.
1693     return m_image->CanEagerBindToModule((Module *)moduleTo);
1694 }
1695
1696 CORINFO_MODULE_HANDLE CEEPreloader::GetPreferredZapModuleForClassHandle(
1697         CORINFO_CLASS_HANDLE classHnd)
1698 {
1699     STANDARD_VM_CONTRACT;
1700
1701     return CORINFO_MODULE_HANDLE(Module::GetPreferredZapModuleForTypeHandle(TypeHandle(classHnd)));
1702 }
1703
1704 // This method is called directly from zapper
1705 extern BOOL CanDeduplicateCode(CORINFO_METHOD_HANDLE method, CORINFO_METHOD_HANDLE duplicateMethod);
1706
1707 BOOL CanDeduplicateCode(CORINFO_METHOD_HANDLE method, CORINFO_METHOD_HANDLE duplicateMethod)
1708 {
1709     CONTRACTL
1710     {
1711         NOTHROW;
1712         GC_NOTRIGGER;
1713     }
1714     CONTRACTL_END;
1715
1716     ENABLE_FORBID_GC_LOADER_USE_IN_THIS_SCOPE();
1717
1718     // For now, the deduplication is supported for IL stubs only
1719     DynamicMethodDesc * pMethod = GetMethod(method)->AsDynamicMethodDesc();
1720     DynamicMethodDesc * pDuplicateMethod = GetMethod(duplicateMethod)->AsDynamicMethodDesc();
1721
1722     //
1723     // Make sure that the return types match (for code:Thread::HijackThread)
1724     //
1725
1726 #ifdef _TARGET_X86_
1727     MetaSig msig1(pMethod);
1728     MetaSig msig2(pDuplicateMethod);
1729     if (!msig1.HasFPReturn() != !msig2.HasFPReturn())
1730         return FALSE;
1731 #endif // _TARGET_X86_
1732
1733     MetaSig::RETURNTYPE returnType = pMethod->ReturnsObject();
1734     MetaSig::RETURNTYPE returnTypeDuplicate = pDuplicateMethod->ReturnsObject();
1735
1736     if (returnType != returnTypeDuplicate)
1737         return FALSE;
1738
1739     //
1740     // Do not enable deduplication of structs returned in registers
1741     //
1742
1743     if (returnType == MetaSig::RETVALUETYPE)
1744         return FALSE;
1745
1746     //
1747     // Make sure that the IL stub flags match
1748     //
1749
1750     if (pMethod->GetExtendedFlags() != pDuplicateMethod->GetExtendedFlags())
1751         return FALSE;
1752
1753     return TRUE;
1754 }
1755
1756 void CEEPreloader::NoteDeduplicatedCode(CORINFO_METHOD_HANDLE method, CORINFO_METHOD_HANDLE duplicateMethod)
1757 {
1758     STANDARD_VM_CONTRACT;
1759
1760 #ifndef FEATURE_FULL_NGEN // Deduplication
1761     DuplicateMethodEntry e;
1762     e.pMD = GetMethod(method);
1763     e.pDuplicateMD = GetMethod(duplicateMethod);
1764     m_duplicateMethodsHash.Add(e);
1765 #endif
1766 }
1767
1768 HRESULT CEECompileInfo::GetFieldDef(CORINFO_FIELD_HANDLE fieldHandle,
1769                                     mdFieldDef *token)
1770 {
1771     STANDARD_VM_CONTRACT;
1772
1773     CANNOTTHROWCOMPLUSEXCEPTION();
1774
1775     *token = ((FieldDesc*)fieldHandle)->GetMemberDef();
1776
1777     return S_OK;
1778 }
1779
1780 void CEECompileInfo::EncodeModuleAsIndexes(CORINFO_MODULE_HANDLE  fromHandle,
1781                                            CORINFO_MODULE_HANDLE  handle,
1782                                            DWORD*                 pAssemblyIndex,
1783                                            DWORD*                 pModuleIndex,
1784                                            IMetaDataAssemblyEmit* pAssemblyEmit)
1785 {
1786     STANDARD_VM_CONTRACT;
1787
1788     COOPERATIVE_TRANSITION_BEGIN();
1789
1790     Module *fromModule = GetModule(fromHandle);
1791     Assembly *fromAssembly = fromModule->GetAssembly();
1792
1793     Module *module = GetModule(handle);
1794     Assembly *assembly = module->GetAssembly();
1795
1796     if (assembly == fromAssembly)
1797         *pAssemblyIndex = 0;
1798     else
1799     {
1800         UPTR    result;
1801         mdToken token;
1802
1803         CompilationDomain *pDomain = GetAppDomain()->ToCompilationDomain();
1804     
1805         RefCache *pRefCache = pDomain->GetRefCache(fromModule);
1806         if (!pRefCache)
1807             ThrowOutOfMemory();
1808
1809         
1810         if (!assembly->GetManifestFile()->HasBindableIdentity())
1811         {
1812             // If the module that we'd like to encode for a later fixup doesn't have
1813             // a bindable identity, then this will fail at runtime. So, we ask the
1814             // compilation domain for a matching assembly with a bindable identity.
1815             // This is possible because this module must have been bound in the past,
1816             // and the compilation domain will keep track of at least one corresponding
1817             // bindable identity.
1818             AssemblySpec defSpec;
1819             defSpec.InitializeSpec(assembly->GetManifestFile());
1820
1821             AssemblySpec* pRefSpec = pDomain->FindAssemblyRefSpecForDefSpec(&defSpec);
1822             _ASSERTE(pRefSpec != nullptr);
1823
1824             IfFailThrow(pRefSpec->EmitToken(pAssemblyEmit, &token, TRUE, TRUE));
1825             token += fromModule->GetAssemblyRefMax();
1826         }
1827         else
1828         {
1829             result = pRefCache->m_sAssemblyRefMap.LookupValue((UPTR)assembly, NULL);
1830
1831             if (result == (UPTR)INVALIDENTRY)
1832                 token = fromModule->FindAssemblyRef(assembly);
1833             else
1834                 token = (mdAssemblyRef) result;
1835
1836             if (IsNilToken(token))
1837             {
1838                 token = fromAssembly->AddAssemblyRef(assembly, pAssemblyEmit);
1839                 token += fromModule->GetAssemblyRefMax();
1840             }
1841         }
1842
1843         *pAssemblyIndex = RidFromToken(token);
1844
1845         pRefCache->m_sAssemblyRefMap.InsertValue((UPTR) assembly, (UPTR)token);
1846     }
1847
1848     if (module == assembly->GetManifestModule())
1849         *pModuleIndex = 0;
1850     else
1851     {
1852         _ASSERTE(module->GetModuleRef() != mdFileNil);
1853         *pModuleIndex = RidFromToken(module->GetModuleRef());
1854     }
1855
1856     COOPERATIVE_TRANSITION_END();
1857 }
1858
1859 void CEECompileInfo::EncodeClass(
1860                          CORINFO_MODULE_HANDLE referencingModule,
1861                          CORINFO_CLASS_HANDLE  classHandle,
1862                          SigBuilder *          pSigBuilder,
1863                          LPVOID                pEncodeModuleContext,
1864                          ENCODEMODULE_CALLBACK pfnEncodeModule)
1865 {
1866     STANDARD_VM_CONTRACT;
1867
1868     TypeHandle th(classHandle);
1869
1870     ZapSig zapSig((Module *)referencingModule, pEncodeModuleContext, ZapSig::NormalTokens,
1871                   (EncodeModuleCallback) pfnEncodeModule, NULL);
1872
1873     COOPERATIVE_TRANSITION_BEGIN();
1874
1875     BOOL fSuccess;
1876     fSuccess = zapSig.GetSignatureForTypeHandle(th, pSigBuilder);
1877     _ASSERTE(fSuccess);
1878
1879     COOPERATIVE_TRANSITION_END();
1880 }
1881
1882 CORINFO_MODULE_HANDLE CEECompileInfo::GetLoaderModuleForMscorlib()
1883 {
1884     STANDARD_VM_CONTRACT;
1885
1886     return CORINFO_MODULE_HANDLE(SystemDomain::SystemModule());
1887 }
1888
1889 CORINFO_MODULE_HANDLE CEECompileInfo::GetLoaderModuleForEmbeddableType(CORINFO_CLASS_HANDLE clsHnd)
1890 {
1891     STANDARD_VM_CONTRACT;
1892
1893     TypeHandle t = TypeHandle(clsHnd);
1894     return CORINFO_MODULE_HANDLE(t.GetLoaderModule());
1895 }
1896
1897 CORINFO_MODULE_HANDLE CEECompileInfo::GetLoaderModuleForEmbeddableMethod(CORINFO_METHOD_HANDLE methHnd)
1898 {
1899     STANDARD_VM_CONTRACT;
1900
1901     MethodDesc *pMD = GetMethod(methHnd);
1902     return CORINFO_MODULE_HANDLE(pMD->GetLoaderModule());
1903 }
1904
1905 CORINFO_MODULE_HANDLE CEECompileInfo::GetLoaderModuleForEmbeddableField(CORINFO_FIELD_HANDLE fieldHnd)
1906 {
1907     STANDARD_VM_CONTRACT;
1908
1909     FieldDesc *pFD = (FieldDesc *) fieldHnd;
1910     return CORINFO_MODULE_HANDLE(pFD->GetLoaderModule());
1911 }
1912
1913 void CEECompileInfo::EncodeMethod(
1914                           CORINFO_MODULE_HANDLE referencingModule,
1915                           CORINFO_METHOD_HANDLE handle,
1916                           SigBuilder *          pSigBuilder,
1917                           LPVOID                pEncodeModuleContext,
1918                           ENCODEMODULE_CALLBACK pfnEncodeModule,
1919                           CORINFO_RESOLVED_TOKEN * pResolvedToken,
1920                           CORINFO_RESOLVED_TOKEN * pConstrainedResolvedToken,
1921                           BOOL                  fEncodeUsingResolvedTokenSpecStreams)
1922 {
1923     STANDARD_VM_CONTRACT;
1924
1925     COOPERATIVE_TRANSITION_BEGIN();
1926     MethodDesc *pMethod = GetMethod(handle);
1927
1928     BOOL fSuccess;
1929     fSuccess = ZapSig::EncodeMethod(pMethod, 
1930                               (Module *) referencingModule,
1931                               pSigBuilder,
1932                               pEncodeModuleContext, 
1933                               pfnEncodeModule, NULL,
1934                               pResolvedToken, pConstrainedResolvedToken,
1935                               fEncodeUsingResolvedTokenSpecStreams);
1936     _ASSERTE(fSuccess);
1937
1938     COOPERATIVE_TRANSITION_END();
1939 }
1940
1941 mdToken CEECompileInfo::TryEncodeMethodAsToken(
1942                 CORINFO_METHOD_HANDLE handle,
1943                 CORINFO_RESOLVED_TOKEN * pResolvedToken,
1944                 CORINFO_MODULE_HANDLE * referencingModule)
1945 {
1946     STANDARD_VM_CONTRACT;
1947
1948     MethodDesc * pMethod = GetMethod(handle);
1949
1950 #ifdef FEATURE_READYTORUN_COMPILER
1951     if (IsReadyToRunCompilation())
1952     {
1953         _ASSERTE(pResolvedToken != NULL);
1954
1955         Module * pReferencingModule = (Module *)pResolvedToken->tokenScope;
1956
1957         if (!pReferencingModule->IsInCurrentVersionBubble())
1958             return mdTokenNil;
1959
1960         unsigned methodToken = pResolvedToken->token;
1961
1962         switch (TypeFromToken(methodToken))
1963         {
1964         case mdtMethodDef:
1965             if (pReferencingModule->LookupMethodDef(methodToken) != pMethod)
1966                 return mdTokenNil;
1967             break;
1968
1969         case mdtMemberRef:
1970             if (pReferencingModule->LookupMemberRefAsMethod(methodToken) != pMethod)
1971                 return mdTokenNil;
1972             break;
1973
1974         default:
1975             return mdTokenNil;
1976         }
1977
1978         *referencingModule = CORINFO_MODULE_HANDLE(pReferencingModule);
1979         return methodToken;
1980     }
1981 #endif // FEATURE_READYTORUN_COMPILER
1982
1983     Module *pModule = pMethod->GetModule();
1984     if (!pModule->IsInCurrentVersionBubble())
1985     {
1986         Module * pTargetModule = GetAppDomain()->ToCompilationDomain()->GetTargetModule();
1987         *referencingModule = CORINFO_MODULE_HANDLE(pTargetModule);
1988         return pTargetModule->LookupMemberRefByMethodDesc(pMethod);
1989     }
1990     else
1991     {
1992         mdToken defToken = pMethod->GetMemberDef();
1993         if (pModule->LookupMethodDef(defToken) == pMethod)
1994         {
1995             *referencingModule = CORINFO_MODULE_HANDLE(pModule);
1996             return defToken;
1997         }
1998     }
1999
2000     return mdTokenNil;
2001 }
2002
2003 DWORD CEECompileInfo::TryEncodeMethodSlot(CORINFO_METHOD_HANDLE handle)
2004 {
2005     STANDARD_VM_CONTRACT;
2006
2007     MethodDesc * pMethod = GetMethod(handle);
2008
2009 #ifdef FEATURE_READYTORUN_COMPILER
2010     if (IsReadyToRunCompilation())
2011     {
2012         // We can only encode real interface methods as slots
2013         if (!pMethod->IsInterface() || pMethod->IsStatic())
2014             return (DWORD)-1;
2015
2016         // And only if the interface lives in the current version bubble
2017         // If may be possible to relax this restriction if we can guarantee that the external interfaces are
2018         // really not changing. We will play it safe for now.
2019         if (!pMethod->GetModule()->IsInCurrentVersionBubble())
2020             return (DWORD)-1;
2021     }
2022 #endif
2023
2024     return pMethod->GetSlot();
2025 }
2026
2027 void EncodeTypeInDictionarySignature(
2028             Module * pInfoModule,
2029             SigPointer ptr, 
2030             SigBuilder * pSigBuilder,
2031             LPVOID encodeContext,
2032             ENCODEMODULE_CALLBACK pfnEncodeModule)
2033 {
2034     STANDARD_VM_CONTRACT;
2035
2036     CorElementType typ = ELEMENT_TYPE_END;
2037     IfFailThrow(ptr.GetElemType(&typ));
2038
2039     if (typ == ELEMENT_TYPE_INTERNAL)
2040     {
2041         TypeHandle th;
2042
2043         IfFailThrow(ptr.GetPointer((void**)&th));
2044
2045         ZapSig zapSig(pInfoModule, encodeContext, ZapSig::NormalTokens,
2046                       (EncodeModuleCallback) pfnEncodeModule, NULL);
2047
2048         //
2049         // Write class
2050         //
2051         BOOL fSuccess;
2052         fSuccess = zapSig.GetSignatureForTypeHandle(th, pSigBuilder);
2053         _ASSERTE(fSuccess);
2054
2055         return;
2056     }
2057     else
2058     if (typ == ELEMENT_TYPE_GENERICINST)
2059     {
2060         //
2061         // SigParser expects ELEMENT_TYPE_MODULE_ZAPSIG to be before ELEMENT_TYPE_GENERICINST
2062         //
2063         SigPointer peek(ptr);
2064         ULONG instType = 0;
2065         IfFailThrow(peek.GetData(&instType));
2066         _ASSERTE(instType == ELEMENT_TYPE_INTERNAL);
2067
2068         TypeHandle th;
2069         IfFailThrow(peek.GetPointer((void **)&th));
2070
2071         Module * pTypeHandleModule = th.GetModule();
2072
2073         if (!pTypeHandleModule->IsInCurrentVersionBubble())
2074         {
2075             pTypeHandleModule = GetAppDomain()->ToCompilationDomain()->GetTargetModule();
2076         }
2077
2078         if (pTypeHandleModule != pInfoModule)
2079         {
2080             DWORD index = pfnEncodeModule(encodeContext, (CORINFO_MODULE_HANDLE)pTypeHandleModule);
2081             _ASSERTE(index != ENCODE_MODULE_FAILED);
2082
2083             pSigBuilder->AppendElementType((CorElementType) ELEMENT_TYPE_MODULE_ZAPSIG);
2084             pSigBuilder->AppendData(index);
2085         }
2086
2087         pSigBuilder->AppendElementType(ELEMENT_TYPE_GENERICINST);
2088
2089         EncodeTypeInDictionarySignature(pTypeHandleModule, ptr, pSigBuilder, encodeContext, pfnEncodeModule);
2090         IfFailThrow(ptr.SkipExactlyOne());
2091
2092         ULONG argCnt = 0; // Get number of parameters
2093         IfFailThrow(ptr.GetData(&argCnt));
2094         pSigBuilder->AppendData(argCnt);
2095
2096         while (argCnt--)
2097         {
2098             EncodeTypeInDictionarySignature(pInfoModule, ptr, pSigBuilder, encodeContext, pfnEncodeModule);
2099             IfFailThrow(ptr.SkipExactlyOne());
2100         }
2101
2102         return;
2103     }
2104
2105     pSigBuilder->AppendElementType(typ);
2106
2107     if (!CorIsPrimitiveType(typ))
2108     {
2109         switch (typ)
2110         {
2111             case ELEMENT_TYPE_VAR:
2112             case ELEMENT_TYPE_MVAR:
2113                 {
2114                     ULONG varNum;
2115                     // Skip variable number
2116                     IfFailThrow(ptr.GetData(&varNum));
2117                     pSigBuilder->AppendData(varNum);
2118                 }
2119                 break;
2120             case ELEMENT_TYPE_OBJECT:
2121             case ELEMENT_TYPE_STRING:
2122             case ELEMENT_TYPE_TYPEDBYREF:
2123                 break;
2124
2125             case ELEMENT_TYPE_BYREF: //fallthru
2126             case ELEMENT_TYPE_PTR:
2127             case ELEMENT_TYPE_PINNED:
2128             case ELEMENT_TYPE_SZARRAY:
2129                 EncodeTypeInDictionarySignature(pInfoModule, ptr, pSigBuilder, encodeContext, pfnEncodeModule);
2130                 IfFailThrow(ptr.SkipExactlyOne());
2131                 break;
2132
2133             case ELEMENT_TYPE_ARRAY:
2134                 {
2135                     EncodeTypeInDictionarySignature(pInfoModule, ptr, pSigBuilder, encodeContext, pfnEncodeModule);
2136                     IfFailThrow(ptr.SkipExactlyOne());
2137
2138                     ULONG rank = 0; // Get rank
2139                     IfFailThrow(ptr.GetData(&rank));
2140                     pSigBuilder->AppendData(rank);
2141
2142                     if (rank)
2143                     {
2144                         ULONG nsizes = 0;
2145                         IfFailThrow(ptr.GetData(&nsizes));
2146                         pSigBuilder->AppendData(nsizes);
2147
2148                         while (nsizes--)
2149                         {
2150                             ULONG data = 0;
2151                             IfFailThrow(ptr.GetData(&data));
2152                             pSigBuilder->AppendData(data);
2153                         }
2154
2155                         ULONG nlbounds = 0;
2156                         IfFailThrow(ptr.GetData(&nlbounds));
2157                         pSigBuilder->AppendData(nlbounds);
2158
2159                         while (nlbounds--)
2160                         {
2161                             ULONG data = 0;
2162                             IfFailThrow(ptr.GetData(&data));
2163                             pSigBuilder->AppendData(data);
2164                         }
2165                     }
2166                 }
2167                 break;
2168
2169             default:
2170                 _ASSERTE(!"Unexpected element in signature");
2171         }
2172     }
2173 }
2174
2175 void CEECompileInfo::EncodeGenericSignature(
2176             LPVOID signature,
2177             BOOL fMethod,
2178             SigBuilder * pSigBuilder,
2179             LPVOID encodeContext,
2180             ENCODEMODULE_CALLBACK pfnEncodeModule)
2181 {
2182     STANDARD_VM_CONTRACT;
2183
2184     Module * pInfoModule = MscorlibBinder::GetModule();
2185
2186     SigPointer ptr((PCCOR_SIGNATURE)signature);
2187
2188     ULONG entryKind; // DictionaryEntryKind
2189     IfFailThrow(ptr.GetData(&entryKind));
2190     pSigBuilder->AppendData(entryKind);
2191
2192     if (!fMethod)
2193     {
2194         ULONG dictionaryIndex = 0;
2195         IfFailThrow(ptr.GetData(&dictionaryIndex));
2196
2197         pSigBuilder->AppendData(dictionaryIndex);
2198     }
2199
2200     switch (entryKind)
2201     {
2202     case DeclaringTypeHandleSlot:
2203         EncodeTypeInDictionarySignature(pInfoModule, ptr, pSigBuilder, encodeContext, pfnEncodeModule);
2204         IfFailThrow(ptr.SkipExactlyOne());
2205         // fall through
2206
2207     case TypeHandleSlot:
2208         EncodeTypeInDictionarySignature(pInfoModule, ptr, pSigBuilder, encodeContext, pfnEncodeModule);
2209         IfFailThrow(ptr.SkipExactlyOne());
2210         break;
2211
2212     case ConstrainedMethodEntrySlot:
2213         EncodeTypeInDictionarySignature(pInfoModule, ptr, pSigBuilder, encodeContext, pfnEncodeModule);
2214         IfFailThrow(ptr.SkipExactlyOne());
2215         // fall through
2216
2217     case MethodDescSlot:
2218     case MethodEntrySlot:
2219     case DispatchStubAddrSlot:
2220         {
2221             EncodeTypeInDictionarySignature(pInfoModule, ptr, pSigBuilder, encodeContext, pfnEncodeModule);
2222             IfFailThrow(ptr.SkipExactlyOne());
2223
2224             ULONG methodFlags;
2225             IfFailThrow(ptr.GetData(&methodFlags));
2226             pSigBuilder->AppendData(methodFlags);
2227
2228             if ((methodFlags & ENCODE_METHOD_SIG_SlotInsteadOfToken) == 0)
2229             {
2230                 EncodeTypeInDictionarySignature(pInfoModule, ptr, pSigBuilder, encodeContext, pfnEncodeModule);
2231                 IfFailThrow(ptr.SkipExactlyOne());
2232             }
2233             
2234             ULONG tokenOrSlot;
2235             IfFailThrow(ptr.GetData(&tokenOrSlot));
2236             pSigBuilder->AppendData(tokenOrSlot);
2237
2238             if (methodFlags & ENCODE_METHOD_SIG_MethodInstantiation)
2239             {
2240                 DWORD nGenericMethodArgs;
2241                 IfFailThrow(ptr.GetData(&nGenericMethodArgs));
2242                 pSigBuilder->AppendData(nGenericMethodArgs);
2243
2244                 for (DWORD i = 0; i < nGenericMethodArgs; i++)
2245                 {
2246                     EncodeTypeInDictionarySignature(pInfoModule, ptr, pSigBuilder, encodeContext, pfnEncodeModule);
2247                     IfFailThrow(ptr.SkipExactlyOne());
2248                 }
2249             }
2250         }
2251         break;
2252
2253     case FieldDescSlot:
2254         {
2255             EncodeTypeInDictionarySignature(pInfoModule, ptr, pSigBuilder, encodeContext, pfnEncodeModule);
2256             IfFailThrow(ptr.SkipExactlyOne());
2257
2258             DWORD fieldIndex;
2259             IfFailThrow(ptr.GetData(&fieldIndex));
2260             pSigBuilder->AppendData(fieldIndex);
2261         }
2262         break;
2263
2264     default:
2265         _ASSERTE(false);
2266     }
2267
2268     ULONG dictionarySlot;
2269     IfFailThrow(ptr.GetData(&dictionarySlot));
2270     pSigBuilder->AppendData(dictionarySlot);
2271 }
2272
2273 void CEECompileInfo::EncodeField(
2274                          CORINFO_MODULE_HANDLE referencingModule,
2275                          CORINFO_FIELD_HANDLE  handle,
2276                          SigBuilder *          pSigBuilder,
2277                          LPVOID                encodeContext,
2278                          ENCODEMODULE_CALLBACK pfnEncodeModule,
2279                          CORINFO_RESOLVED_TOKEN * pResolvedToken, 
2280                          BOOL fEncodeUsingResolvedTokenSpecStreams)
2281 {
2282     STANDARD_VM_CONTRACT;
2283
2284     COOPERATIVE_TRANSITION_BEGIN();
2285
2286     ZapSig::EncodeField(GetField(handle), 
2287                         (Module *) referencingModule,
2288                         pSigBuilder,
2289                         encodeContext, 
2290                         pfnEncodeModule,
2291                         pResolvedToken,
2292                         fEncodeUsingResolvedTokenSpecStreams);
2293
2294     COOPERATIVE_TRANSITION_END();
2295 }
2296
2297 BOOL CEECompileInfo::IsEmptyString(mdString token,
2298                                    CORINFO_MODULE_HANDLE module)
2299 {
2300     STANDARD_VM_CONTRACT;
2301
2302     BOOL fRet = FALSE;
2303
2304     COOPERATIVE_TRANSITION_BEGIN();
2305
2306     EEStringData strData;
2307     ((Module *)module)->InitializeStringData(token, &strData, NULL);
2308     fRet = (strData.GetCharCount() == 0);
2309
2310     COOPERATIVE_TRANSITION_END();
2311
2312     return fRet;
2313 }
2314
2315 #ifdef FEATURE_READYTORUN_COMPILER
2316 CORCOMPILE_FIXUP_BLOB_KIND CEECompileInfo::GetFieldBaseOffset(
2317         CORINFO_CLASS_HANDLE classHnd,
2318         DWORD * pBaseOffset)
2319 {
2320     STANDARD_VM_CONTRACT;
2321
2322     MethodTable * pMT = (MethodTable *)classHnd;
2323     Module * pModule = pMT->GetModule();
2324
2325     if (!pMT->IsLayoutFixedInCurrentVersionBubble())
2326     {
2327         return pMT->IsValueType() ? ENCODE_CHECK_FIELD_OFFSET : ENCODE_FIELD_OFFSET;
2328     }
2329
2330     if (pMT->IsValueType())
2331     {
2332         return ENCODE_NONE;
2333     }
2334
2335     if (pMT->GetParentMethodTable()->IsInheritanceChainLayoutFixedInCurrentVersionBubble())
2336     {
2337         return ENCODE_NONE;
2338     }
2339
2340     if (pMT->HasLayout())
2341     {
2342         // We won't try to be smart for classes with layout.
2343         // They are complex to get right, and very rare anyway.
2344         return ENCODE_FIELD_OFFSET;
2345     }
2346
2347     *pBaseOffset = ReadyToRunInfo::GetFieldBaseOffset(pMT);
2348     return ENCODE_FIELD_BASE_OFFSET;
2349 }
2350
2351 BOOL CEECompileInfo::NeedsTypeLayoutCheck(CORINFO_CLASS_HANDLE classHnd)
2352 {
2353     STANDARD_VM_CONTRACT;
2354
2355     TypeHandle th(classHnd);
2356
2357     if (th.IsTypeDesc())
2358         return FALSE;
2359
2360     MethodTable * pMT = th.AsMethodTable();
2361
2362     if (!pMT->IsValueType())
2363         return FALSE;
2364
2365     // Skip this check for equivalent types. Equivalent types are used for interop that ensures
2366     // matching layout.
2367     if (pMT->GetClass()->IsEquivalentType())
2368         return FALSE;
2369
2370     return !pMT->IsLayoutFixedInCurrentVersionBubble();
2371 }
2372
2373 extern void ComputeGCRefMap(MethodTable * pMT, BYTE * pGCRefMap, size_t cbGCRefMap);
2374
2375 void CEECompileInfo::EncodeTypeLayout(CORINFO_CLASS_HANDLE classHandle, SigBuilder * pSigBuilder)
2376 {
2377     STANDARD_VM_CONTRACT;
2378
2379     MethodTable * pMT = TypeHandle(classHandle).AsMethodTable();
2380     _ASSERTE(pMT->IsValueType());
2381
2382     DWORD dwSize = pMT->GetNumInstanceFieldBytes();
2383     DWORD dwAlignment = CEEInfo::getClassAlignmentRequirementStatic(pMT);
2384
2385     DWORD dwFlags = 0;
2386
2387 #ifdef FEATURE_HFA
2388     if (pMT->IsHFA())
2389         dwFlags |= READYTORUN_LAYOUT_HFA;
2390 #endif
2391
2392     // Check everything 
2393     dwFlags |= READYTORUN_LAYOUT_Alignment;
2394     if (dwAlignment == sizeof(void *))
2395         dwFlags |= READYTORUN_LAYOUT_Alignment_Native;
2396
2397     dwFlags |= READYTORUN_LAYOUT_GCLayout;
2398     if (!pMT->ContainsPointers())
2399         dwFlags |= READYTORUN_LAYOUT_GCLayout_Empty;
2400
2401     pSigBuilder->AppendData(dwFlags);
2402
2403     // Size is checked unconditionally
2404     pSigBuilder->AppendData(dwSize);
2405
2406 #ifdef FEATURE_HFA
2407     if (dwFlags & READYTORUN_LAYOUT_HFA)
2408     {
2409         pSigBuilder->AppendData(pMT->GetHFAType());
2410     }
2411 #endif
2412
2413     if ((dwFlags & READYTORUN_LAYOUT_Alignment) && !(dwFlags & READYTORUN_LAYOUT_Alignment_Native))
2414     {
2415         pSigBuilder->AppendData(dwAlignment);
2416     }
2417
2418     if ((dwFlags & READYTORUN_LAYOUT_GCLayout) && !(dwFlags & READYTORUN_LAYOUT_GCLayout_Empty))
2419     {
2420         size_t cbGCRefMap = (dwSize / sizeof(TADDR) + 7) / 8;
2421         _ASSERTE(cbGCRefMap > 0);
2422
2423         BYTE * pGCRefMap = (BYTE *)_alloca(cbGCRefMap);
2424
2425         ComputeGCRefMap(pMT, pGCRefMap, cbGCRefMap);
2426
2427         for (size_t i = 0; i < cbGCRefMap; i++)
2428             pSigBuilder->AppendByte(pGCRefMap[i]);
2429     }
2430 }
2431
2432 BOOL CEECompileInfo::AreAllClassesFullyLoaded(CORINFO_MODULE_HANDLE moduleHandle)
2433 {
2434     STANDARD_VM_CONTRACT;
2435
2436     return ((Module *)moduleHandle)->AreAllClassesFullyLoaded();
2437 }
2438
2439 int CEECompileInfo::GetVersionResilientTypeHashCode(CORINFO_MODULE_HANDLE moduleHandle, mdToken token)
2440 {
2441     STANDARD_VM_CONTRACT;
2442
2443     int dwHashCode;
2444     if (!::GetVersionResilientTypeHashCode(((Module *)moduleHandle)->GetMDImport(), token, &dwHashCode))
2445         ThrowHR(COR_E_BADIMAGEFORMAT);
2446
2447     return dwHashCode;
2448 }
2449
2450 int CEECompileInfo::GetVersionResilientMethodHashCode(CORINFO_METHOD_HANDLE methodHandle)
2451 {
2452     STANDARD_VM_CONTRACT;
2453
2454     return ::GetVersionResilientMethodHashCode(GetMethod(methodHandle));
2455 }
2456
2457 #endif // FEATURE_READYTORUN_COMPILER
2458
2459 BOOL CEECompileInfo::HasCustomAttribute(CORINFO_METHOD_HANDLE method, LPCSTR customAttributeName)
2460 {
2461     STANDARD_VM_CONTRACT;
2462
2463     MethodDesc * pMD = GetMethod(method);
2464     return S_OK == pMD->GetMDImport()->GetCustomAttributeByName(pMD->GetMemberDef(), customAttributeName, NULL, NULL);
2465 }
2466
2467 #define OMFConst_Read            0x0001
2468 #define OMFConst_Write           0x0002
2469 #define OMFConst_Exec            0x0004
2470 #define OMFConst_F32Bit          0x0008
2471 #define OMFConst_ReservedBits1   0x00f0
2472 #define OMFConst_FSel            0x0100
2473 #define OMFConst_FAbs            0x0200
2474 #define OMFConst_ReservedBits2   0x0C00
2475 #define OMFConst_FGroup          0x1000
2476 #define OMFConst_ReservedBits3   0xE000
2477
2478 #define OMF_StandardText  (OMFConst_FSel|OMFConst_F32Bit|OMFConst_Exec|OMFConst_Read) // 0x10D
2479 #define OMF_SentinelType  (OMFConst_FAbs|OMFConst_F32Bit) // 0x208
2480
2481
2482 // ----------------------------------------------------------------------------
2483 // NGEN PDB SUPPORT
2484 // 
2485 // The NGEN PDB format consists of structs stacked together into buffers, which are
2486 // passed to the PDB API. For a description of the structures, see
2487 // InternalApis\vctools\inc\cvinfo.h.
2488 // 
2489 // The interface to the PDB used below is NGEN-specific, and is exposed via
2490 // diasymreader.dll. For a description of this interface, see ISymNGenWriter2 inside
2491 // public\devdiv\inc\corsym.h and debugger\sh\symwrtr\ngenpdbwriter.h,cpp
2492 // ----------------------------------------------------------------------------
2493
2494 #if defined(NO_NGENPDB) && !defined(FEATURE_PERFMAP)
2495 BOOL CEECompileInfo::GetIsGeneratingNgenPDB() 
2496 {
2497     return FALSE; 
2498 }
2499
2500 void CEECompileInfo::SetIsGeneratingNgenPDB(BOOL fGeneratingNgenPDB) 
2501 {
2502 }
2503
2504 BOOL IsNgenPDBCompilationProcess()
2505 {
2506     return FALSE;
2507 }
2508 #else
2509 BOOL CEECompileInfo::GetIsGeneratingNgenPDB() 
2510 {
2511     LIMITED_METHOD_DAC_CONTRACT;
2512     return m_fGeneratingNgenPDB; 
2513 }
2514
2515 void CEECompileInfo::SetIsGeneratingNgenPDB(BOOL fGeneratingNgenPDB) 
2516 {
2517     LIMITED_METHOD_DAC_CONTRACT;
2518     m_fGeneratingNgenPDB = fGeneratingNgenPDB; 
2519 }
2520
2521 BOOL IsNgenPDBCompilationProcess()
2522 {
2523     LIMITED_METHOD_DAC_CONTRACT;
2524     return IsCompilationProcess() && g_pCEECompileInfo->GetIsGeneratingNgenPDB();
2525 }
2526
2527 #endif // NO_NGENPDB && !FEATURE_PERFMAP
2528
2529 #ifndef NO_NGENPDB
2530 // This is the prototype of "CreateNGenPdbWriter" exported by diasymreader.dll 
2531 typedef HRESULT (__stdcall *CreateNGenPdbWriter_t)(const WCHAR *pwszNGenImagePath, const WCHAR *pwszPdbPath, void **ppvObj);
2532
2533 // Allocator to specify when requesting boundaries information for PDB
2534 BYTE* SimpleNew(void *, size_t cBytes)
2535 {
2536     CONTRACTL
2537     {
2538         THROWS;
2539         GC_NOTRIGGER;
2540         MODE_ANY;
2541     }
2542     CONTRACTL_END;
2543
2544     BYTE * p = new BYTE[cBytes];
2545     return p;
2546 }
2547
2548 // PDB convention has any IPs that don't map to source code (e.g., prolog, epilog, etc.)
2549 // to be mapped to line number "0xFeeFee".
2550 const int kUnmappedIP = 0xFeeFee;
2551
2552
2553 // ----------------------------------------------------------------------------
2554 // Simple pair of offsets for each source file name.  Pair includes its offset into the
2555 // PDB string table, and its offset in the files checksum table.
2556 // 
2557 struct DocNameOffsets
2558 {
2559     ULONG32 m_dwStrTableOffset;
2560     ULONG32 m_dwChksumTableOffset;
2561     DocNameOffsets(ULONG32 dwStrTableOffset, ULONG32 dwChksumTableOffset)
2562         : m_dwStrTableOffset(dwStrTableOffset), m_dwChksumTableOffset(dwChksumTableOffset)
2563     {
2564         LIMITED_METHOD_CONTRACT;
2565     }
2566
2567     DocNameOffsets()
2568         : m_dwStrTableOffset((ULONG32) -1), m_dwChksumTableOffset((ULONG32) -1)
2569     {
2570         LIMITED_METHOD_CONTRACT;
2571     }
2572 };
2573
2574
2575 // ----------------------------------------------------------------------------
2576 // This is used when creating the hash table which maps source file names to
2577 // DocNameOffsets instances.  The only interesting stuff here is that:
2578 //     * Equality is determined by a case-insensitive comparison on the source file
2579 //         names
2580 //     * Hashing is done by hashing the source file names
2581 //     
2582 struct DocNameToOffsetMapTraits : public NoRemoveSHashTraits < MapSHashTraits<LPCSTR, DocNameOffsets> >
2583 {
2584 public:
2585     static BOOL Equals(key_t k1, key_t k2)
2586     {
2587         LIMITED_METHOD_CONTRACT;
2588
2589         if (k1 == NULL && k2 == NULL)
2590             return TRUE;
2591         if (k1 == NULL || k2 == NULL)
2592             return FALSE;
2593         return _stricmp(k1, k2) == 0;
2594     }
2595
2596     static count_t Hash(key_t k)
2597     {
2598         LIMITED_METHOD_CONTRACT;
2599
2600         if (k == NULL)
2601             return 0;
2602         else
2603             return HashiStringA(k);
2604     }
2605
2606     typedef LPCSTR KEY;
2607     typedef DocNameOffsets VALUE;
2608     typedef NoRemoveSHashTraits < MapSHashTraits<LPCSTR, DocNameOffsets> > PARENT;
2609     typedef PARENT::element_t element_t;
2610     static const element_t Null() { LIMITED_METHOD_CONTRACT; return element_t((KEY)0,VALUE((ULONG32) -1, (ULONG32) -1)); }
2611     static bool IsNull(const element_t &e) { LIMITED_METHOD_CONTRACT; return e.Key() == (KEY)0; }
2612 };
2613
2614
2615 // ----------------------------------------------------------------------------
2616 // Hash table that maps the UTF-8 string of a source file name to its corresponding
2617 // DocNameToOffsetMapTraits
2618 // 
2619 class DocNameToOffsetMap : public SHash<DocNameToOffsetMapTraits>
2620 {
2621     typedef SHash<DocNameToOffsetMapTraits> PARENT;
2622     typedef LPCSTR KEY;
2623     typedef DocNameOffsets VALUE;
2624     
2625 public:
2626     void Add(KEY key, VALUE value)
2627     {
2628         CONTRACTL
2629         {
2630             THROWS;
2631             GC_NOTRIGGER;
2632             PRECONDITION(key != (KEY)0);
2633         }
2634         CONTRACTL_END;
2635
2636         PARENT::Add(KeyValuePair<KEY,VALUE>(key, value));
2637     }
2638
2639     void AddOrReplace(KEY key, VALUE value)
2640     {
2641         CONTRACTL
2642         {
2643             THROWS;
2644             GC_NOTRIGGER;
2645             PRECONDITION(key != (KEY)0);
2646         }
2647         CONTRACTL_END;
2648
2649         PARENT::AddOrReplace(KeyValuePair<KEY,VALUE>(key, value));
2650     }
2651
2652     BOOL Lookup(KEY key, VALUE* pValue)
2653     {
2654         CONTRACTL
2655         {
2656             NOTHROW;
2657             GC_NOTRIGGER;
2658             PRECONDITION(key != (KEY)0);
2659         }
2660         CONTRACTL_END;
2661
2662         const KeyValuePair<KEY,VALUE> *pRet = PARENT::LookupPtr(key);
2663         if (pRet == NULL)
2664             return FALSE;
2665
2666         *pValue = pRet->Value();
2667         return TRUE;
2668     }
2669 };
2670
2671 // ----------------------------------------------------------------------------
2672 // Simple class to sort ICorDebugInfo::OffsetMapping arrays by IL offset
2673 // 
2674 class QuickSortILNativeMapByIL : public CQuickSort<ICorDebugInfo::OffsetMapping>
2675 {
2676   public:
2677     QuickSortILNativeMapByIL(
2678         ICorDebugInfo::OffsetMapping * rgMap,
2679         int cEntries)
2680       : CQuickSort<ICorDebugInfo::OffsetMapping>(rgMap, cEntries)
2681     {
2682         LIMITED_METHOD_CONTRACT;
2683     }
2684
2685     int Compare(ICorDebugInfo::OffsetMapping * pFirst,
2686                 ICorDebugInfo::OffsetMapping * pSecond)
2687     {
2688         LIMITED_METHOD_CONTRACT;
2689
2690         if (pFirst->ilOffset < pSecond->ilOffset)
2691             return -1;
2692         else if (pFirst->ilOffset == pSecond->ilOffset)
2693             return 0;
2694         else
2695             return 1;
2696     }
2697 };
2698
2699 // ----------------------------------------------------------------------------
2700 // Simple class to sort IL to Native mapping arrays by Native offset
2701 // 
2702 class QuickSortILNativeMapByNativeOffset : public CQuickSort<ICorDebugInfo::OffsetMapping>
2703 {
2704 public:
2705     QuickSortILNativeMapByNativeOffset(
2706         ICorDebugInfo::OffsetMapping * rgMap,
2707         int cEntries)
2708         : CQuickSort<ICorDebugInfo::OffsetMapping>(rgMap, cEntries)
2709     {
2710         LIMITED_METHOD_CONTRACT;
2711     }
2712
2713     int Compare(ICorDebugInfo::OffsetMapping * pFirst,
2714         ICorDebugInfo::OffsetMapping * pSecond)
2715     {
2716         LIMITED_METHOD_CONTRACT;
2717
2718         if (pFirst->nativeOffset < pSecond->nativeOffset)
2719             return -1;
2720         else if (pFirst->nativeOffset == pSecond->nativeOffset)
2721             return 0;
2722         else
2723             return 1;
2724     }
2725 };
2726
2727 // ----------------------------------------------------------------------------
2728 // Simple structure used when merging the JIT manager's IL-to-native maps
2729 // (ICorDebugInfo::OffsetMapping) with the IL PDB's source-to-IL map.
2730 // 
2731 struct MapIndexPair
2732 {
2733 public:
2734     // Index into ICorDebugInfo::OffsetMapping
2735     ULONG32 m_iIlNativeMap;
2736     
2737     // Corresponding index into the IL PDB's sequence point arrays
2738     ULONG32 m_iSeqPoints;
2739
2740     MapIndexPair() : 
2741         m_iIlNativeMap((ULONG32) -1), 
2742         m_iSeqPoints((ULONG32) -1)
2743     {
2744         LIMITED_METHOD_CONTRACT;
2745     }
2746 };
2747
2748 // ----------------------------------------------------------------------------
2749 // Simple class to sort MapIndexPairs by native IP offset. A MapIndexPair sorts "earlier"
2750 // if its m_iIlNativeMap index gives you an IP offset (i.e.,
2751 // m_rgIlNativeMap[m_iIlNativeMap].nativeOffset) that is smaller.
2752 // 
2753 class QuickSortMapIndexPairsByNativeOffset : public CQuickSort<MapIndexPair>
2754 {
2755   public:
2756     QuickSortMapIndexPairsByNativeOffset(
2757         MapIndexPair * rgMap, 
2758         int cEntries, 
2759         ICorDebugInfo::OffsetMapping * rgIlNativeMap,
2760         ULONG32 cIlNativeMap)
2761         : CQuickSort<MapIndexPair>(rgMap, cEntries),
2762           m_rgIlNativeMap(rgIlNativeMap),
2763           m_cIlNativeMap(cIlNativeMap)
2764     {
2765         LIMITED_METHOD_CONTRACT;
2766     }
2767
2768     int Compare(MapIndexPair * pFirst,
2769                 MapIndexPair * pSecond)
2770     {
2771         LIMITED_METHOD_CONTRACT;
2772
2773         _ASSERTE(pFirst->m_iIlNativeMap < m_cIlNativeMap);
2774         _ASSERTE(pSecond->m_iIlNativeMap < m_cIlNativeMap);
2775
2776         DWORD dwFirstNativeOffset = m_rgIlNativeMap[pFirst->m_iIlNativeMap].nativeOffset;
2777         DWORD dwSecondNativeOffset = m_rgIlNativeMap[pSecond->m_iIlNativeMap].nativeOffset;
2778
2779         if (dwFirstNativeOffset < dwSecondNativeOffset)
2780             return -1;
2781         else if (dwFirstNativeOffset == dwSecondNativeOffset)
2782             return 0;
2783         else
2784             return 1;
2785     }
2786
2787 protected:
2788     ICorDebugInfo::OffsetMapping * m_rgIlNativeMap;
2789     ULONG32 m_cIlNativeMap;
2790 };
2791
2792 // ----------------------------------------------------------------------------
2793 // The following 3 classes contain the code to generate PDBs
2794 // 
2795
2796 // NGEN always generates PDBs with public symbols lists (so tools can map IP ranges to
2797 // methods).  This bitmask indicates what extra info should be added to the PDB
2798 enum PDBExtraData
2799 {
2800     // Add string table subsection, files checksum subsection, and lines subsection to
2801     // allow tools to map IP ranges to source lines.
2802     kPDBLines  = 0x00000001,
2803 };
2804
2805
2806 // ----------------------------------------------------------------------------
2807 // Manages generating all PDB data for an NGENd image.  One of these is instantiated per
2808 // run of "ngen createpdb"
2809 // 
2810 class NGenPdbWriter
2811 {
2812 private:
2813     CreateNGenPdbWriter_t m_Create;
2814     HMODULE m_hModule;
2815     ReleaseHolder<ISymUnmanagedBinder> m_pBinder;
2816     LPCWSTR m_wszPdbPath;
2817     DWORD m_dwExtraData;
2818     LPCWSTR m_wszManagedPDBSearchPath;
2819
2820 public:
2821     NGenPdbWriter (LPCWSTR wszNativeImagePath, LPCWSTR wszPdbPath, DWORD dwExtraData, LPCWSTR wszManagedPDBSearchPath)
2822         : m_hModule(NULL),
2823           m_Create(NULL),
2824           m_wszPdbPath(wszPdbPath),
2825           m_dwExtraData(dwExtraData),
2826           m_wszManagedPDBSearchPath(wszManagedPDBSearchPath)
2827     {
2828         LIMITED_METHOD_CONTRACT;
2829     }
2830
2831 #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")
2832
2833     HRESULT Load(LPCWSTR wszDiasymreaderPath = nullptr)
2834     {
2835         STANDARD_VM_CONTRACT;
2836
2837         HRESULT hr = S_OK;
2838
2839         m_hModule = WszLoadLibrary(wszDiasymreaderPath != nullptr ? wszDiasymreaderPath : (LPCWSTR)NATIVE_SYMBOL_READER_DLL);
2840         if (m_hModule == NULL)
2841         {
2842             hr = HRESULT_FROM_WIN32(GetLastError());
2843             GetSvcLogger()->Printf(WRITER_LOAD_ERROR_MESSAGE, GetLastError());
2844             return hr;
2845         }
2846
2847         m_Create = reinterpret_cast<CreateNGenPdbWriter_t>(GetProcAddress(m_hModule, "CreateNGenPdbWriter"));
2848         if (m_Create == NULL)
2849         {
2850             hr = HRESULT_FROM_WIN32(GetLastError());
2851             GetSvcLogger()->Printf(WRITER_LOAD_ERROR_MESSAGE, GetLastError());
2852             return hr;
2853         }
2854
2855         if ((m_dwExtraData & kPDBLines) != 0)
2856         {
2857             hr = FakeCoCreateInstanceEx(
2858                 CLSID_CorSymBinder_SxS,
2859                 wszDiasymreaderPath != nullptr ? wszDiasymreaderPath : (LPCWSTR)NATIVE_SYMBOL_READER_DLL,
2860                 IID_ISymUnmanagedBinder,
2861                 (void**)&m_pBinder,
2862                 NULL);
2863         }
2864
2865         return hr;
2866     }
2867
2868     HRESULT WritePDBDataForModule(Module * pModule);
2869
2870     ~NGenPdbWriter()
2871     {
2872         LIMITED_METHOD_CONTRACT;
2873
2874         if (m_hModule)
2875             FreeLibrary(m_hModule);
2876
2877         m_Create = NULL;
2878     }
2879 };
2880
2881 #define UNKNOWN_SOURCE_FILE_PATH L"unknown"
2882
2883 // ----------------------------------------------------------------------------
2884 // Manages generating all PDB data for an EE Module. Directly responsible for writing the
2885 // string table and file checksum subsections. One of these is instantiated per Module
2886 // found when using the ModuleIterator over the CORINFO_ASSEMBLY_HANDLE corresponding to
2887 // this invocation of NGEN createpdb.
2888 // 
2889 class NGenModulePdbWriter
2890 {
2891 private:
2892     // Simple holder to coordinate the PDB calls to OpenModW and CloseMod on a given PDB
2893     // Mod *.
2894     class PDBModHolder
2895     {
2896     private:
2897         ReleaseHolder<ISymNGenWriter2> m_pWriter;
2898         LPBYTE m_pMod;
2899
2900     public:
2901         PDBModHolder()
2902             : m_pWriter(NULL),
2903               m_pMod(NULL)
2904         {
2905             LIMITED_METHOD_CONTRACT;
2906         }
2907
2908         ~PDBModHolder()
2909         {
2910             LIMITED_METHOD_CONTRACT;
2911
2912             if ((m_pWriter != NULL) && (m_pMod != NULL))
2913             {
2914                 m_pWriter->CloseMod(m_pMod);
2915             }
2916         }
2917
2918         HRESULT Open(ISymNGenWriter2 * pWriter, LPCWSTR wszModule, LPCWSTR wszObjFile)
2919         {
2920             LIMITED_METHOD_CONTRACT;
2921
2922             _ASSERTE(m_pWriter == NULL);
2923
2924             m_pWriter = pWriter;
2925             m_pWriter->AddRef();
2926
2927             _ASSERTE(m_pMod == NULL);
2928
2929             HRESULT hr = m_pWriter->OpenModW(wszModule, wszObjFile, &m_pMod);
2930             if (FAILED(hr))
2931             {
2932                 m_pMod = NULL;
2933             }
2934             return hr;
2935         }
2936
2937         LPBYTE GetModPtr()
2938         {
2939             LIMITED_METHOD_CONTRACT;
2940
2941             _ASSERTE(m_pMod != NULL);
2942             return m_pMod;
2943         }
2944     };
2945
2946 private:
2947     // This holder ensures we delete a half-generated PDB file if we manage to create it
2948     // on disk, but fail at some point after it was created. When NGenModulePdbWriter is
2949     // destroyed, m_deletePDBFileHolder's destructor will delete the PDB file if there
2950     // was a prior error.
2951     // 
2952     //************* NOTE! *************
2953     // 
2954     // These members should appear FIRST so that they get destructed last. That way, if
2955     // we encounter an error generating the PDB file, we ensure that we release all PDB
2956     // interfaces and close the PDB file BEFORE this holder tries to *delete* the PDB
2957     // file. Also, keep these two in this relative order, so that m_deletePDBFileHolder
2958     // is destructed before m_wszPDBFilePath.
2959     WCHAR m_wszPDBFilePath[MAX_LONGPATH];
2960     DeleteFileHolder m_deletePDBFileHolder;
2961     // 
2962     // ************* NOTE! *************
2963     
2964     CreateNGenPdbWriter_t m_Create;
2965     LPCWSTR m_wszPdbPath;
2966     ReleaseHolder<ISymNGenWriter2> m_pWriter;
2967     Module * m_pModule;
2968     DWORD m_dwExtraData;
2969     LPCWSTR m_wszManagedPDBSearchPath;
2970
2971         // Currently The DiasymWriter does not use the correct PDB signature for NGEN PDBS unless 
2972         // the NGEN DLL whose symbols are being generated end in .ni.dll.   Thus we copy
2973         // to this name if it does not follow this covention (as is true with readyToRun
2974         // dlls).   This variable remembers this temp file path so we can delete it after
2975         // Pdb generation.   If DiaSymWriter is fixed, we can remove this.  
2976         SString m_tempSourceDllName;
2977
2978     // Interfaces for reading IL PDB info
2979     ReleaseHolder<ISymUnmanagedBinder> m_pBinder;
2980     ReleaseHolder<ISymUnmanagedReader> m_pReader;
2981     NewInterfaceArrayHolder<ISymUnmanagedDocument> m_rgpDocs;       // All docs in the PDB Mod
2982         // I know m_ilPdbCount and m_finalPdbDocCount are confusing.Here is the reason :
2983         // For NGenMethodLinesPdbWriter::WriteDebugSILLinesSubsection, we won't write the path info.  
2984         // In order to let WriteDebugSILLinesSubsection find "UNKNOWN_SOURCE_FILE_PATH" which does 
2985         // not exist in m_rgpDocs, no matter if we have IL PDB or not, we let m_finalPdbDocCount 
2986         // equal m_ilPdbDocCount + 1 and write the extra one path as "UNKNOWN_SOURCE_FILE_PATH"
2987     ULONG32 m_ilPdbDocCount;
2988     ULONG32 m_finalPdbDocCount;
2989
2990     // Keeps track of source file names and how they map to offsets in the relevant PDB
2991     // subsections.
2992     DocNameToOffsetMap m_docNameToOffsetMap;
2993
2994     // Holds a PDB Mod *
2995     PDBModHolder m_pdbMod;
2996
2997     // Buffer in which to store the entire string table (i.e., list of all source file
2998     // names).  This buffer is held alive as long as m_docNameToOffsetMap is needed, as
2999     // the latter contains offsets into this buffer.
3000     NewArrayHolder<BYTE> m_rgbStringTableSubsection;
3001
3002     HRESULT InitILPdbData();
3003     HRESULT WriteStringTable();
3004     HRESULT WriteFileChecksums();
3005
3006 public:
3007     NGenModulePdbWriter(CreateNGenPdbWriter_t Create, LPCWSTR wszPdbPath, DWORD dwExtraData, ISymUnmanagedBinder * pBinder, Module * pModule, LPCWSTR wszManagedPDBSearchPath)
3008         : m_Create(Create),
3009           m_wszPdbPath(wszPdbPath),
3010           m_pWriter(NULL),
3011           m_dwExtraData(dwExtraData),
3012           m_pBinder(pBinder),
3013           m_pModule(pModule),
3014           m_wszManagedPDBSearchPath(wszManagedPDBSearchPath),
3015           m_ilPdbDocCount(0),
3016           m_finalPdbDocCount(1)
3017     {
3018         LIMITED_METHOD_CONTRACT;
3019
3020         if (m_pBinder != NULL)
3021             m_pBinder->AddRef();
3022
3023         ZeroMemory(m_wszPDBFilePath, sizeof(m_wszPDBFilePath));
3024     }
3025
3026         ~NGenModulePdbWriter();
3027     
3028     HRESULT WritePDBData();
3029
3030     HRESULT WriteMethodPDBData(PEImageLayout * pLoadedLayout, USHORT iCodeSection, BYTE *pCodeBase, MethodDesc * hotDesc, PCODE start, bool isILPDBProvided);
3031 };
3032
3033 // ----------------------------------------------------------------------------
3034 // Manages generating the lines subsection in the PDB data for a given managed method.
3035 // One of these is instantiated per managed method we find when iterating through all
3036 // methods in a Module.
3037 // 
3038 class NGenMethodLinesPdbWriter
3039 {
3040 private:
3041     ISymNGenWriter2 * m_pWriter;
3042     LPBYTE m_pMod;
3043     ISymUnmanagedReader * m_pReader;
3044     MethodDesc * m_hotDesc;
3045     PCODE m_start;
3046     USHORT m_iCodeSection;
3047     TADDR m_addrCodeSection;
3048     const IJitManager::MethodRegionInfo * m_pMethodRegionInfo;
3049     EECodeInfo * m_pCodeInfo;
3050     DocNameToOffsetMap * m_pDocNameToOffsetMap;
3051     bool m_isILPDBProvided;
3052
3053     // IL-to-native map from JIT manager
3054     ULONG32 m_cIlNativeMap;
3055     NewArrayHolder<ICorDebugInfo::OffsetMapping> m_rgIlNativeMap;
3056
3057     // IL PDB info for this one method
3058     NewInterfaceArrayHolder<ISymUnmanagedDocument> m_rgpDocs;  // Source files defining this method.
3059     NewArrayHolder<ULONG32> m_rgilOffsets;                     // Array of IL offsets for this method
3060     NewArrayHolder<ULONG32> m_rgnLineStarts;                   // Array of source lines for this method
3061     ULONG32 m_cSeqPoints;                                      // Count of above two parallel arrays
3062
3063     HRESULT WriteNativeILMapPDBData();
3064     LPBYTE InitDebugLinesHeaderSection(
3065         DEBUG_S_SUBSECTION_TYPE type,
3066         ULONG32 ulCodeStartOffset,
3067         ULONG32 cbCode,
3068         ULONG32 lineSize,
3069         CV_DebugSSubsectionHeader_t **ppSubSectHeader /*out*/,
3070         CV_DebugSLinesHeader_t ** ppLinesHeader /*out*/,
3071         LPBYTE * ppbLinesSubsectionCur /*out*/);
3072
3073     HRESULT WriteDebugSLinesSubsection(
3074         ULONG32 ulCodeStartOffset,
3075         ULONG32 cbCode,
3076         MapIndexPair * rgMapIndexPairs,
3077         ULONG32 cMapIndexPairs);
3078
3079     HRESULT WriteDebugSILLinesSubsection(
3080         ULONG32 ulCodeStartOffset,
3081         ULONG32 cbCode,
3082         ICorDebugInfo::OffsetMapping * rgILNativeMap,
3083         ULONG32 rgILNativeMapAdjustSize);
3084
3085     BOOL FinalizeLinesFileBlock(
3086         CV_DebugSLinesFileBlockHeader_t * pLinesFileBlockHeader,
3087         CV_Line_t * pLineBlockStart,
3088         CV_Line_t * pLineBlockAfterEnd
3089 #ifdef _DEBUG
3090         , BOOL ignorekUnmappedIPCheck = false
3091 #endif
3092         );
3093
3094 public:
3095     NGenMethodLinesPdbWriter(
3096         ISymNGenWriter2 * pWriter,
3097         LPBYTE pMod,
3098         ISymUnmanagedReader * pReader,
3099         MethodDesc * hotDesc,
3100         PCODE start, 
3101         USHORT iCodeSection, 
3102         TADDR addrCodeSection,
3103         const IJitManager::MethodRegionInfo * pMethodRegionInfo,
3104         EECodeInfo * pCodeInfo,
3105         DocNameToOffsetMap * pDocNameToOffsetMap,
3106         bool isILPDBProvided)
3107         : m_pWriter(pWriter),
3108           m_pMod(pMod),
3109           m_pReader(pReader),
3110           m_hotDesc(hotDesc),
3111           m_start(start),
3112           m_iCodeSection(iCodeSection),
3113           m_addrCodeSection(addrCodeSection),
3114           m_pMethodRegionInfo(pMethodRegionInfo),
3115           m_pCodeInfo(pCodeInfo),
3116           m_pDocNameToOffsetMap(pDocNameToOffsetMap),
3117           m_cIlNativeMap(0),
3118           m_cSeqPoints(0),
3119           m_isILPDBProvided(isILPDBProvided)
3120     {
3121         LIMITED_METHOD_CONTRACT;
3122     }
3123
3124     HRESULT WritePDBData();
3125 };
3126
3127 // ----------------------------------------------------------------------------
3128 // NGenPdbWriter implementation
3129
3130
3131
3132 //---------------------------------------------------------------------------------------
3133 //
3134 // Coordinates calling all the other classes & methods to generate PDB info for the
3135 // given Module
3136 //
3137 // Arguments:
3138 //      pModule - EE Module to write PDB data for
3139 //
3140
3141 HRESULT NGenPdbWriter::WritePDBDataForModule(Module * pModule)
3142 {
3143     STANDARD_VM_CONTRACT;
3144     NGenModulePdbWriter ngenModulePdbWriter(m_Create, m_wszPdbPath, m_dwExtraData, m_pBinder, pModule, m_wszManagedPDBSearchPath);
3145     return ngenModulePdbWriter.WritePDBData();
3146 }
3147
3148
3149 // ----------------------------------------------------------------------------
3150 // NGenModulePdbWriter implementation
3151
3152
3153 //---------------------------------------------------------------------------------------
3154 //
3155 // Writes out all source files into the string table subsection for the PDB Mod*
3156 // controlled by this NGenModulePdbWriter.  Updates m_docNameToOffsetMap to add string
3157 // table offset for each source file as it gets added.
3158 // 
3159 HRESULT NGenModulePdbWriter::WriteStringTable()
3160 {
3161     STANDARD_VM_CONTRACT;
3162
3163     _ASSERTE(m_pWriter != NULL);
3164
3165     HRESULT hr;
3166     UINT64 cbStringTableEstimate =
3167         sizeof(DWORD) +
3168         sizeof(CV_DebugSSubsectionHeader_t) +
3169         m_finalPdbDocCount * (MAX_LONGPATH + 1);
3170     if (!FitsIn<ULONG32>(cbStringTableEstimate))
3171     {
3172         return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
3173     }
3174     
3175     m_rgbStringTableSubsection = new BYTE[ULONG32(cbStringTableEstimate)];
3176     LPBYTE pbStringTableSubsectionCur = m_rgbStringTableSubsection;
3177
3178     // Subsection signature
3179     *((DWORD *) pbStringTableSubsectionCur) = CV_SIGNATURE_C13;
3180     pbStringTableSubsectionCur += sizeof(DWORD);
3181
3182     // Subsection header
3183     CV_DebugSSubsectionHeader_t * pSubSectHeader = (CV_DebugSSubsectionHeader_t *) pbStringTableSubsectionCur;
3184     memset(pSubSectHeader, 0, sizeof(*pSubSectHeader));
3185     pSubSectHeader->type = DEBUG_S_STRINGTABLE;
3186     pbStringTableSubsectionCur += sizeof(*pSubSectHeader);
3187     // pSubSectHeader->cbLen counts the number of bytes that appear AFTER the subsection
3188     // header above (i.e., the size of the string table itself). We'll fill out
3189     // pSubSectHeader->cbLen below, once it's calculated
3190
3191     LPBYTE pbStringTableStart = pbStringTableSubsectionCur;
3192
3193     // The actual strings
3194     for (ULONG32 i = 0; i < m_finalPdbDocCount; i++)
3195     {
3196         // For NGenMethodLinesPdbWriter::WriteDebugSILLinesSubsection, we won't write the path info.  
3197         // In order to let WriteDebugSILLinesSubsection can find "UNKNOWN_SOURCE_FILE_PATH" which is 
3198         // not existed in m_rgpDocs, no matter we have IL PDB or not, we let m_finalPdbDocCount equals to 
3199         // m_ilPdbDocCount + 1 and write the extra one path as "UNKNOWN_SOURCE_FILE_PATH". That also explains
3200         // why we have a inconsistence between m_finalPdbDocCount and m_ilPdbDocCount.
3201         WCHAR wszURL[MAX_LONGPATH] = UNKNOWN_SOURCE_FILE_PATH;
3202         ULONG32 cchURL;
3203         if (i < m_ilPdbDocCount)
3204         {
3205             hr = m_rgpDocs[i]->GetURL(_countof(wszURL), &cchURL, wszURL);
3206             if (FAILED(hr))
3207                 return hr;
3208         }
3209         int cbWritten = WideCharToMultiByte(
3210             CP_UTF8,
3211             0,                                      // dwFlags
3212             wszURL,
3213             -1,                                     // i.e., input is NULL-terminated
3214             (LPSTR) pbStringTableSubsectionCur,     // output: UTF8 string starts here
3215             ULONG32(cbStringTableEstimate) - 
3216                 int(pbStringTableSubsectionCur - m_rgbStringTableSubsection),    // Available space
3217             NULL,                                   // lpDefaultChar
3218             NULL                                    // lpUsedDefaultChar
3219             );
3220         if (cbWritten == 0)
3221             return HRESULT_FROM_WIN32(GetLastError());
3222
3223         // Remember the string table offset for later
3224         m_docNameToOffsetMap.AddOrReplace(
3225             (LPCSTR) pbStringTableSubsectionCur, 
3226             DocNameOffsets(
3227                 ULONG32(pbStringTableSubsectionCur - pbStringTableStart),
3228                 (ULONG32) -1));
3229         
3230         pbStringTableSubsectionCur += cbWritten;
3231         if (pbStringTableSubsectionCur >= (m_rgbStringTableSubsection + cbStringTableEstimate))
3232             return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
3233     }
3234
3235     // Now that we know pSubSectHeader->cbLen, fill it in
3236     pSubSectHeader->cbLen = CV_off32_t(pbStringTableSubsectionCur - pbStringTableStart);
3237
3238     // Subsection is now filled out, so use the PDB API to add it
3239     hr = m_pWriter->ModAddSymbols(
3240         m_pdbMod.GetModPtr(),
3241         m_rgbStringTableSubsection, 
3242         int(pbStringTableSubsectionCur - m_rgbStringTableSubsection));
3243     if (FAILED(hr))
3244         return hr;
3245
3246     return S_OK;
3247 }
3248
3249 //---------------------------------------------------------------------------------------
3250 //
3251 // This takes care of actually loading the IL PDB itself, and initializing the
3252 // ISymUnmanaged* interfaces with module-level data from the IL PDB.
3253 // 
3254 HRESULT NGenModulePdbWriter::InitILPdbData()
3255 {
3256     // Load the managed PDB
3257     
3258     ReleaseHolder<IUnknown> pUnk = NULL;
3259     HRESULT hr = m_pModule->GetReadablePublicMetaDataInterface(ofReadOnly, IID_IMetaDataImport, (LPVOID *) &pUnk);
3260     if (FAILED(hr))
3261     {
3262         GetSvcLogger()->Printf(
3263             W("Unable to obtain metadata for '%s'  Error: '0x%x'.\n"),
3264             LPCWSTR(m_pModule->GetFile()->GetILimage()->GetPath()),
3265             hr);
3266         return hr;
3267     }
3268
3269     hr = m_pBinder->GetReaderForFile(
3270         pUnk,
3271         m_pModule->GetFile()->GetILimage()->GetPath(),
3272         m_wszManagedPDBSearchPath,
3273         &m_pReader);
3274     if (FAILED(hr))
3275     {
3276         GetSvcLogger()->Printf(
3277             W("Unable to find managed PDB matching '%s'.  Managed PDB search path: '%s'\n"),
3278             LPCWSTR(m_pModule->GetFile()->GetILimage()->GetPath()),
3279             (((m_wszManagedPDBSearchPath == NULL) || (*m_wszManagedPDBSearchPath == W('\0'))) ?
3280                 W("(not specified)") :
3281                 m_wszManagedPDBSearchPath));
3282         return hr;
3283     }
3284
3285     GetSvcLogger()->Log(W("Loaded managed PDB"));
3286
3287     // Grab the full path of the managed PDB so we can log it
3288     WCHAR wszIlPdbPath[MAX_LONGPATH];
3289     ULONG32 cchIlPdbPath;
3290     hr = m_pReader->GetSymbolStoreFileName(
3291         _countof(wszIlPdbPath),
3292         &cchIlPdbPath,
3293         wszIlPdbPath);
3294     if (FAILED(hr))
3295     {
3296         GetSvcLogger()->Log(W("\n"));
3297     }
3298     else
3299     {
3300         GetSvcLogger()->Printf(W(": '%s'\n"), wszIlPdbPath);
3301     }
3302
3303     // Read all source files names from the IL PDB
3304     ULONG32 cDocs;
3305     hr = m_pReader->GetDocuments(
3306         0,              // cDocsRequested
3307         &cDocs,
3308         NULL            // Array
3309         );
3310     if (FAILED(hr))
3311         return hr;
3312     
3313     m_rgpDocs = new ISymUnmanagedDocument * [cDocs];
3314     hr = m_pReader->GetDocuments(
3315         cDocs,
3316         &m_ilPdbDocCount,
3317         m_rgpDocs);
3318     if (FAILED(hr))
3319         return hr;
3320     m_finalPdbDocCount = m_ilPdbDocCount + 1;
3321     // Commit m_rgpDocs to calling Release() on each ISymUnmanagedDocument* in the array
3322     m_rgpDocs.SetElementCount(m_ilPdbDocCount);
3323     
3324     return S_OK;
3325 }
3326
3327 NGenModulePdbWriter::~NGenModulePdbWriter()
3328 {
3329         // Delete any temporary files we created. 
3330         if (m_tempSourceDllName.GetCount() != 0)
3331                 DeleteFileW(m_tempSourceDllName);
3332         m_tempSourceDllName.Clear();
3333 }
3334
3335 //---------------------------------------------------------------------------------------
3336 //
3337 // This manages writing all Module-level data to the PDB, including public symbols,
3338 // string table, files checksum, section contribution table, and, indirectly, the lines
3339 // subsection
3340 // 
3341 HRESULT NGenModulePdbWriter::WritePDBData()
3342 {
3343     STANDARD_VM_CONTRACT;
3344
3345     _ASSERTE(m_pWriter == NULL);
3346
3347     HRESULT hr;
3348
3349     // This will try to open the managed PDB if lines info was requested.  This is a
3350     // likely failure point, so intentionally do this before creating the NGEN PDB file
3351     // on disk.
3352     bool isILPDBProvided = false;
3353     if ((m_dwExtraData & kPDBLines) != 0)
3354     {
3355         hr = InitILPdbData();
3356         if (FAILED(hr))
3357             return hr;
3358         isILPDBProvided = true;
3359     }
3360
3361     // Create the PDB file we will write into.
3362
3363     _ASSERTE(m_Create != NULL);
3364     _ASSERTE(m_pModule != NULL);
3365
3366     PEImageLayout * pLoadedLayout = m_pModule->GetFile()->GetLoaded();
3367
3368         // Currently DiaSymReader does not work properly generating NGEN PDBS unless 
3369         // the DLL whose PDB is being generated ends in .ni.*.   Unfortunately, readyToRun
3370         // images do not follow this convention and end up producing bad PDBS.  To fix
3371         // this (without changing diasymreader.dll which ships indepdendently of .Net Core)
3372         // we copy the file to somethign with this convention before generating the PDB
3373         // and delete it when we are done.  
3374         SString dllPath = pLoadedLayout->GetPath();
3375         if (!dllPath.EndsWithCaseInsensitive(L".ni.dll") && !dllPath.EndsWithCaseInsensitive(L".ni.exe"))
3376         {
3377                 SString::Iterator fileNameStart = dllPath.Begin();
3378                 dllPath.FindBack(fileNameStart, '\\');
3379
3380                 SString::Iterator ext = dllPath.End();
3381                 dllPath.FindBack(ext, '.');
3382
3383                 // m_tempSourceDllName = Convertion of  INPUT.dll  to INPUT.ni.dll where the PDB lives.  
3384                 m_tempSourceDllName = m_wszPdbPath;
3385                 m_tempSourceDllName += SString(dllPath, fileNameStart, ext - fileNameStart);
3386                 m_tempSourceDllName += L".ni";
3387                 m_tempSourceDllName += SString(dllPath, ext, dllPath.End() - ext);
3388                 CopyFileW(dllPath, m_tempSourceDllName, false);
3389                 dllPath = m_tempSourceDllName;
3390         }
3391
3392     ReleaseHolder<ISymNGenWriter> pWriter1;
3393     hr = m_Create(dllPath, m_wszPdbPath, &pWriter1);
3394     if (FAILED(hr))
3395         return hr;
3396     
3397     hr = pWriter1->QueryInterface(IID_ISymNGenWriter2, (LPVOID*) &m_pWriter);
3398     if (FAILED(hr))
3399     {
3400         GetSvcLogger()->Printf(
3401             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"),
3402             hr);
3403         return hr;
3404     }
3405
3406     // PDB file is now created.  Get its path and initialize the holder so the PDB file
3407     // can be deleted if we don't make it successfully to the end
3408
3409     hr = m_pWriter->QueryPDBNameExW(m_wszPDBFilePath, _countof(m_wszPDBFilePath));
3410     if (SUCCEEDED(hr))
3411     {
3412         // A failure in QueryPDBNameExW above isn't fatal--it just means we can't
3413         // initialize m_deletePDBFileHolder, and thus may leave the PDB file on disk if
3414         // there's *another* error later on. And if we do hit another error, NGEN will
3415         // still return an error exit code, so the worst we'll have is a bogus PDB file
3416         // that no one should expect works anyway.
3417         m_deletePDBFileHolder.Assign(m_wszPDBFilePath);
3418     }
3419
3420
3421     hr = m_pdbMod.Open(m_pWriter, pLoadedLayout->GetPath(), m_pModule->GetPath());
3422     if (FAILED(hr))
3423         return hr;
3424
3425     hr = WriteStringTable();
3426     if (FAILED(hr))
3427         return hr;
3428
3429     hr = WriteFileChecksums();
3430     if (FAILED(hr))
3431         return hr;
3432     
3433
3434     COUNT_T sectionCount = pLoadedLayout->GetNumberOfSections();
3435     IMAGE_SECTION_HEADER *section = pLoadedLayout->FindFirstSection();
3436     COUNT_T sectionIndex = 0;
3437     USHORT iCodeSection = 0;
3438     BYTE *pCodeBase = NULL;
3439     while (sectionIndex < sectionCount) 
3440     {
3441         hr = m_pWriter->AddSection((USHORT)(sectionIndex + 1),
3442                                  OMF_StandardText, 
3443                                  0,
3444                                  section[sectionIndex].SizeOfRawData);
3445         if (FAILED(hr))
3446             return hr;
3447
3448         if (strcmp((const char *)&section[sectionIndex].Name[0], ".text") == 0) {
3449             _ASSERTE((iCodeSection == 0) && (pCodeBase == NULL));
3450             iCodeSection = (USHORT)(sectionIndex + 1);
3451             pCodeBase = (BYTE *)section[sectionIndex].VirtualAddress;
3452         }
3453
3454         // In order to support the DIA RVA-to-lines API against the PDB we're
3455         // generating, we need to update the section contribution table with each
3456         // section we add.
3457         hr = m_pWriter->ModAddSecContribEx(
3458             m_pdbMod.GetModPtr(),
3459             (USHORT)(sectionIndex + 1),
3460             0,
3461             section[sectionIndex].SizeOfRawData,
3462             section[sectionIndex].Characteristics,
3463             0,          // dwDataCrc
3464             0           // dwRelocCrc
3465             );
3466         if (FAILED(hr))
3467             return hr;
3468
3469         sectionIndex++;
3470     }
3471
3472     _ASSERTE(iCodeSection != 0);
3473     _ASSERTE(pCodeBase != NULL);
3474
3475
3476     // To support lines info, we need a "dummy" section, indexed as 0, for use as a
3477     // sentinel when MSPDB sets up its section contribution table
3478     hr = m_pWriter->AddSection(0,           // Dummy section 0
3479         OMF_SentinelType, 
3480         0,
3481         0xFFFFffff);
3482     if (FAILED(hr))
3483         return hr;
3484     
3485
3486 #ifdef FEATURE_READYTORUN_COMPILER
3487     if (pLoadedLayout->HasReadyToRunHeader())
3488     {
3489         ReadyToRunInfo::MethodIterator mi(m_pModule->GetReadyToRunInfo());
3490         while (mi.Next())
3491         {
3492             MethodDesc *hotDesc = mi.GetMethodDesc();
3493
3494             hr = WriteMethodPDBData(pLoadedLayout, iCodeSection, pCodeBase, hotDesc, mi.GetMethodStartAddress(), isILPDBProvided);
3495             if (FAILED(hr))
3496                 return hr;
3497         }
3498     }
3499     else
3500 #endif // FEATURE_READYTORUN_COMPILER
3501     {
3502         MethodIterator mi(m_pModule);
3503         while (mi.Next()) 
3504         {
3505             MethodDesc *hotDesc = mi.GetMethodDesc();
3506             hotDesc->CheckRestore();
3507
3508             hr = WriteMethodPDBData(pLoadedLayout, iCodeSection, pCodeBase, hotDesc, mi.GetMethodStartAddress(), isILPDBProvided);
3509             if (FAILED(hr))
3510                 return hr;
3511         }
3512     }
3513
3514     // We made it successfully to the end, so don't delete the PDB file.
3515     m_deletePDBFileHolder.SuppressRelease();
3516     return S_OK;
3517 }
3518
3519 HRESULT NGenModulePdbWriter::WriteMethodPDBData(PEImageLayout * pLoadedLayout, USHORT iCodeSection, BYTE *pCodeBase, MethodDesc * hotDesc, PCODE start, bool isILPDBProvided)
3520 {
3521     STANDARD_VM_CONTRACT;
3522
3523     HRESULT hr;
3524
3525     EECodeInfo codeInfo(start);
3526     _ASSERTE(codeInfo.IsValid());
3527
3528     IJitManager::MethodRegionInfo methodRegionInfo;
3529     codeInfo.GetMethodRegionInfo(&methodRegionInfo);
3530
3531     PCODE pHotCodeStart = methodRegionInfo.hotStartAddress;
3532     _ASSERTE(pHotCodeStart);
3533
3534     PCODE pColdCodeStart = methodRegionInfo.coldStartAddress;
3535         SString mAssemblyName;
3536         mAssemblyName.SetUTF8(m_pModule->GetAssembly()->GetSimpleName());
3537     SString assemblyName;
3538     assemblyName.SetUTF8(hotDesc->GetAssembly()->GetSimpleName());
3539     SString methodToken;
3540     methodToken.Printf("%X", hotDesc->GetMemberDef());
3541
3542     // Hot name
3543     {
3544         SString fullName;
3545         TypeString::AppendMethodInternal(
3546             fullName, 
3547             hotDesc, 
3548             TypeString::FormatNamespace | TypeString::FormatSignature);
3549                 fullName.Append(L"$#");
3550                 if (!mAssemblyName.Equals(assemblyName))
3551                         fullName.Append(assemblyName);
3552                 fullName.Append(L"#");
3553         fullName.Append(methodToken);
3554         BSTRHolder hotNameHolder(SysAllocString(fullName.GetUnicode()));
3555         hr = m_pWriter->AddSymbol(hotNameHolder,
3556                                 iCodeSection,
3557                                 (pHotCodeStart - (TADDR)pLoadedLayout->GetBase() - (TADDR)pCodeBase));
3558         if (FAILED(hr))
3559             return hr;
3560     }
3561
3562     // Cold name
3563     {
3564         if (pColdCodeStart) {
3565
3566             SString fullNameCold;
3567             fullNameCold.Append(W("[COLD] "));
3568             TypeString::AppendMethodInternal(
3569                 fullNameCold, 
3570                 hotDesc, 
3571                 TypeString::FormatNamespace | TypeString::FormatSignature);
3572                         fullNameCold.Append(L"$#");
3573                         if (!mAssemblyName.Equals(assemblyName))
3574                                 fullNameCold.Append(assemblyName);
3575                         fullNameCold.Append(L"#");
3576             fullNameCold.Append(methodToken);
3577
3578             BSTRHolder coldNameHolder(SysAllocString(fullNameCold.GetUnicode()));
3579             hr = m_pWriter->AddSymbol(coldNameHolder,
3580                                     iCodeSection,
3581                                     (pColdCodeStart - (TADDR)pLoadedLayout->GetBase() - (TADDR)pCodeBase));
3582                 
3583             if (FAILED(hr))
3584                 return hr;
3585
3586         }
3587     }
3588
3589     // Offset / lines mapping
3590     // Skip functions that are too big for PDB lines format
3591     if (FitsIn<DWORD>(methodRegionInfo.hotSize) &&
3592         FitsIn<DWORD>(methodRegionInfo.coldSize))
3593     {
3594         NGenMethodLinesPdbWriter methodLinesWriter(
3595             m_pWriter,
3596             m_pdbMod.GetModPtr(),
3597             m_pReader,
3598             hotDesc, 
3599             start, 
3600             iCodeSection, 
3601             (TADDR)pLoadedLayout->GetBase() + (TADDR)pCodeBase, 
3602             &methodRegionInfo, 
3603             &codeInfo, 
3604             &m_docNameToOffsetMap,
3605             isILPDBProvided);
3606
3607         hr = methodLinesWriter.WritePDBData();
3608         if (FAILED(hr))
3609             return hr;
3610     }
3611
3612     return S_OK;
3613 }
3614
3615 // ----------------------------------------------------------------------------
3616 // Handles writing the file checksums subsection to the PDB
3617 // 
3618 HRESULT NGenModulePdbWriter::WriteFileChecksums()
3619 {
3620     STANDARD_VM_CONTRACT;
3621
3622     _ASSERTE(m_pWriter != NULL);
3623
3624     // The file checksums subsection of the PDB (i.e., "DEBUG_S_FILECHKSMS"), is a blob
3625     // consisting of a few structs stacked one after the other:
3626     // 
3627     // * (1) DWORD = CV_SIGNATURE_C13 -- the usual subsection signature DWORD
3628     // * (2) CV_DebugSSubsectionHeader_t -- the usual subsection header, with type =
3629     //     DEBUG_S_FILECHKSMS
3630     // * (3) Blob consisting of an array of checksum data -- the format of this piece is
3631     //     not defined via structs (not sure why), but is defined in
3632     //     vctools\PDB\doc\lines.docx
3633     //     
3634     HRESULT hr;
3635
3636     // PDB format requires that the checksum size can always be expressed in a BYTE.
3637     const BYTE kcbEachChecksumEstimate = 0xFF;
3638
3639     UINT64 cbChecksumSubsectionEstimate =
3640         sizeof(DWORD) +
3641         sizeof(CV_DebugSSubsectionHeader_t) +
3642         m_finalPdbDocCount * kcbEachChecksumEstimate;
3643     if (!FitsIn<ULONG32>(cbChecksumSubsectionEstimate))
3644     {
3645         return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
3646     }
3647
3648     NewArrayHolder<BYTE> rgbChksumSubsection(new BYTE[ULONG32(cbChecksumSubsectionEstimate)]);
3649     LPBYTE pbChksumSubsectionCur = rgbChksumSubsection;
3650
3651     // (1) Subsection signature
3652     *((DWORD *) pbChksumSubsectionCur) = CV_SIGNATURE_C13;
3653     pbChksumSubsectionCur += sizeof(DWORD);
3654
3655     // (2) Subsection header
3656     CV_DebugSSubsectionHeader_t * pSubSectHeader = (CV_DebugSSubsectionHeader_t *) pbChksumSubsectionCur;
3657     memset(pSubSectHeader, 0, sizeof(*pSubSectHeader));
3658     pSubSectHeader->type = DEBUG_S_FILECHKSMS;
3659     pbChksumSubsectionCur += sizeof(*pSubSectHeader);
3660     // pSubSectHeader->cblen to be filled in later once we know the size
3661
3662     LPBYTE pbChksumDataStart = pbChksumSubsectionCur;
3663
3664     // (3) Iterate through source files, steal their checksum info from the IL PDB, and
3665     // write it into the NGEN PDB.
3666     for (ULONG32 i = 0; i < m_finalPdbDocCount; i++)
3667     {
3668         WCHAR wszURL[MAX_LONGPATH] = UNKNOWN_SOURCE_FILE_PATH;
3669         char szURL[MAX_LONGPATH];
3670         ULONG32 cchURL;
3671
3672
3673         bool isKnownSourcePath = i < m_ilPdbDocCount;
3674         if (isKnownSourcePath)
3675         {
3676             // For NGenMethodLinesPdbWriter::WriteDebugSILLinesSubsection, we won't write the path info.  
3677             // In order to let WriteDebugSILLinesSubsection can find "UNKNOWN_SOURCE_FILE_PATH" which is 
3678             // not existed in m_rgpDocs, no matter we have IL PDB or not, we let m_finalPdbDocCount equals to 
3679             // m_ilPdbDocCount + 1 and write the extra one path as "UNKNOWN_SOURCE_FILE_PATH". That also explains
3680             // why we have a inconsistence between m_finalPdbDocCount and m_ilPdbDocCount.
3681             hr = m_rgpDocs[i]->GetURL(_countof(wszURL), &cchURL, wszURL);
3682             if (FAILED(hr))
3683                 return hr;
3684         }
3685
3686         int cbWritten = WideCharToMultiByte(
3687             CP_UTF8,
3688             0,                                      // dwFlags
3689             wszURL,
3690             -1,                                     // i.e., input is NULL-terminated
3691             szURL,                                  // output: UTF8 string starts here
3692             _countof(szURL),                        // Available space
3693             NULL,                                   // lpDefaultChar
3694             NULL                                    // lpUsedDefaultChar
3695             );
3696         if (cbWritten == 0)
3697             return HRESULT_FROM_WIN32(GetLastError());
3698
3699         // find offset into string table and add to blob; meanwhile update hash to
3700         // remember the offset into the cksum table
3701         const KeyValuePair<LPCSTR,DocNameOffsets> * pMapEntry = 
3702             m_docNameToOffsetMap.LookupPtr(szURL);
3703         if (pMapEntry == NULL)
3704         {
3705             // Should never happen, as it implies we found a source file that was never
3706             // written to the string table
3707             return E_UNEXPECTED;
3708         }
3709         DocNameOffsets docNameOffsets(pMapEntry->Value());
3710         docNameOffsets.m_dwChksumTableOffset = ULONG32(pbChksumSubsectionCur - pbChksumDataStart);
3711
3712         // Update the map with the new docNameOffsets that contains the cksum table
3713         // offset as well. Note that we must ensure the key (LPCSTR) remains the same
3714         // (thus we explicitly ask for the Key()). This class guarantees that string
3715         // pointer (which comes from the string table buffer field) will remain allocated
3716         // as long as the map is.
3717         m_docNameToOffsetMap.AddOrReplace(pMapEntry->Key(), docNameOffsets);
3718         * (ULONG32 *) pbChksumSubsectionCur = docNameOffsets.m_dwStrTableOffset;
3719         pbChksumSubsectionCur += sizeof(ULONG32);
3720
3721         // Checksum algorithm and bytes
3722
3723         BYTE rgbChecksum[kcbEachChecksumEstimate];
3724         ULONG32 cbChecksum = 0;
3725         BYTE bChecksumAlgorithmType = CHKSUM_TYPE_NONE;
3726         if (isKnownSourcePath)
3727         {
3728             GUID guidChecksumAlgorithm;
3729             hr = m_rgpDocs[i]->GetCheckSumAlgorithmId(&guidChecksumAlgorithm);
3730             if (SUCCEEDED(hr))
3731             {
3732                 // If we got the checksum algorithm, we can write it all out to the buffer. 
3733                 // Else, we'll just omit the checksum info
3734                 if (memcmp(&guidChecksumAlgorithm, &CorSym_SourceHash_MD5, sizeof(GUID)) == 0)
3735                     bChecksumAlgorithmType = CHKSUM_TYPE_MD5;
3736                 else if (memcmp(&guidChecksumAlgorithm, &CorSym_SourceHash_SHA1, sizeof(GUID)) == 0)
3737                     bChecksumAlgorithmType = CHKSUM_TYPE_SHA1;
3738             }
3739         }
3740
3741         if (bChecksumAlgorithmType != CHKSUM_TYPE_NONE)
3742         {
3743             hr = m_rgpDocs[i]->GetCheckSum(sizeof(rgbChecksum), &cbChecksum, rgbChecksum);
3744             if (FAILED(hr) || !FitsIn<BYTE>(cbChecksum))
3745             {
3746                 // Should never happen, but just in case checksum data is invalid, just put
3747                 // no checksum into the NGEN PDB
3748                 bChecksumAlgorithmType = CHKSUM_TYPE_NONE;
3749                 cbChecksum = 0;
3750             }
3751         }
3752
3753         // checksum length & algorithm
3754         *pbChksumSubsectionCur = (BYTE) cbChecksum;             
3755         pbChksumSubsectionCur++;
3756         *pbChksumSubsectionCur = bChecksumAlgorithmType;
3757         pbChksumSubsectionCur++;
3758
3759         // checksum data bytes
3760         memcpy(pbChksumSubsectionCur, rgbChecksum, cbChecksum);
3761         pbChksumSubsectionCur += cbChecksum;
3762
3763         // Must align to the next 4-byte boundary
3764         LPBYTE pbChksumSubsectionCurAligned = (LPBYTE) ALIGN_UP(pbChksumSubsectionCur, 4);
3765         memset(pbChksumSubsectionCur, 0, pbChksumSubsectionCurAligned-pbChksumSubsectionCur);
3766         pbChksumSubsectionCur = pbChksumSubsectionCurAligned;
3767     }
3768
3769     // Now that we know pSubSectHeader->cbLen, fill it in
3770     pSubSectHeader->cbLen = CV_off32_t(pbChksumSubsectionCur - pbChksumDataStart);
3771
3772     // Subsection is now filled out, so add it
3773     hr = m_pWriter->ModAddSymbols(
3774         m_pdbMod.GetModPtr(), 
3775         rgbChksumSubsection, 
3776         int(pbChksumSubsectionCur - rgbChksumSubsection));
3777     if (FAILED(hr))
3778         return hr;
3779
3780     return S_OK;
3781 }
3782
3783 // ----------------------------------------------------------------------------
3784 // NGenMethodLinesPdbWriter implementation
3785
3786
3787 //---------------------------------------------------------------------------------------
3788 //
3789 // Manages the writing of all lines-file subsections requred for a given method.  if a
3790 // method is hot/cold split, this will write two line-file subsections to the PDB--one
3791 // for the hot region, and one for the cold.
3792 //
3793
3794 HRESULT NGenMethodLinesPdbWriter::WritePDBData()
3795 {
3796     STANDARD_VM_CONTRACT;
3797
3798     if (m_hotDesc->IsNoMetadata())
3799     {
3800         // IL stubs will not have data in the IL PDB, so just skip them.
3801         return S_OK;
3802     }
3803
3804     //
3805     // First, we'll need to merge the IL-to-native map from the JIT manager with the
3806     // IL-to-source map from the IL PDB. This merging is done into a single piece that
3807     // includes all regions of the code when it's split
3808     // 
3809
3810     // Grab the IL-to-native map from the JIT manager
3811     DebugInfoRequest debugInfoRequest;
3812     debugInfoRequest.InitFromStartingAddr(m_hotDesc, m_start);
3813     BOOL fSuccess = m_pCodeInfo->GetJitManager()->GetBoundariesAndVars(
3814         debugInfoRequest,
3815         SimpleNew, NULL,            // Allocator
3816         &m_cIlNativeMap,
3817         &m_rgIlNativeMap,
3818         NULL, NULL);
3819     if (!fSuccess)
3820     {
3821         // Shouldn't happen, but just skip this method if it does
3822         return S_OK;
3823     }
3824     HRESULT hr;
3825     if (FAILED(hr = WriteNativeILMapPDBData()))
3826     {
3827         return hr;
3828     }
3829
3830     if (!m_isILPDBProvided)
3831     {
3832         return S_OK;
3833     }
3834
3835     // We will traverse this IL-to-native map (from the JIT) in parallel with the
3836     // source-to-IL map provided by the IL PDB (below).  Both need to be sorted by IL so
3837     // we can easily find matching entries in the two maps
3838     QuickSortILNativeMapByIL sorterByIl(m_rgIlNativeMap, m_cIlNativeMap);
3839     sorterByIl.Sort();
3840
3841     // Now grab IL-to-source map from the IL PDBs (just known as "sequence points"
3842     // according to the IL PDB API)
3843     
3844     ReleaseHolder<ISymUnmanagedMethod> pMethod;
3845     hr = m_pReader->GetMethod(
3846         m_hotDesc->GetMemberDef(),
3847         &pMethod);
3848     if (FAILED(hr))
3849     {
3850         // Ignore any methods not included in the IL PDB.  Although we've already
3851         // excluded LCG & IL stubs from methods we're considering, there can still be
3852         // methods in the NGEN module that are not in the IL PDB (e.g., implicit ctors).
3853         return S_OK;
3854     }
3855
3856     ULONG32 cSeqPointsExpected;
3857     hr = pMethod->GetSequencePointCount(&cSeqPointsExpected);
3858     if (FAILED(hr))
3859     {
3860         // Should never happen, but we can just skip this function if the IL PDB can't
3861         // find sequence point info
3862         return S_OK;
3863     }
3864
3865     ULONG32 cSeqPointsReturned;
3866     m_rgilOffsets = new ULONG32[cSeqPointsExpected];
3867     m_rgpDocs = new ISymUnmanagedDocument * [cSeqPointsExpected];
3868     m_rgnLineStarts = new ULONG32[cSeqPointsExpected];
3869     
3870     //  This is guaranteed to return the sequence points sorted in order of the IL
3871     //  offsets (m_rgilOffsets)
3872     hr = pMethod->GetSequencePoints(
3873         cSeqPointsExpected,
3874         &cSeqPointsReturned,
3875         m_rgilOffsets,
3876         m_rgpDocs,
3877         m_rgnLineStarts,
3878         NULL,       // ColumnStarts not needed
3879         NULL,       // LineEnds not needed
3880         NULL);      // ColumnEnds not needed
3881     if (FAILED(hr))
3882     {
3883         // Shouldn't happen, but just skip this method if it does
3884         return S_OK;
3885     }
3886     // Commit m_rgpDocs to calling Release() on all ISymUnmanagedDocument* returned into
3887     // the array.
3888     m_rgpDocs.SetElementCount(cSeqPointsReturned);
3889
3890     // Now merge the two maps together into an array of MapIndexPair structures. Traverse
3891     // both maps in parallel (both ordered by IL offset), looking for IL offset matches.
3892     // Range matching: If an entry in the IL-to-native map has no matching entry in the
3893     // IL PDB, then seek up in the IL PDB to the previous sequence point and merge to
3894     // that (assuming that previous sequence point from the IL PDB did not already have
3895     // an exact match to some other entry in the IL-to-native map).
3896     ULONG32 cMapIndexPairsMax = m_cIlNativeMap;
3897     NewArrayHolder<MapIndexPair> rgMapIndexPairs(new MapIndexPair [cMapIndexPairsMax]);
3898     ULONG32 iSeqPoints = 0;
3899
3900     // Keep track (via iSeqPointLastUnmatched) of the most recent entry in the IL PDB
3901     // that we passed over because it had no matching entry in the IL-to-native map. We
3902     // may use this to do a range-match if necessary. We'll set iSeqPointLastUnmatched to
3903     // the currently interated IL PDB entry after our cursor in the il-to-native map
3904     // passed it by, but only if fCurSeqPointMatched is FALSE
3905     ULONG32 iSeqPointLastUnmatched = (ULONG32) -1;
3906     BOOL fCurSeqPointMatched = FALSE;
3907     
3908     ULONG32 iIlNativeMap = 0;
3909     ULONG32 iMapIndexPairs = 0;
3910         
3911     // Traverse IL PDB entries and IL-to-native map entries (both sorted by IL) in
3912     // parallel
3913     // 
3914     //     * Record matching indices in our output map, rgMapIndexPairs, indexed by
3915     //         iMapIndexPairs.
3916     // 
3917     //     * We will have at most m_cIlNativeMap entries in rgMapIndexPairs by the time
3918     //         we're done. (Each il-to-native map entry will be considered for inclusion
3919     //         in this output. Those il-to-native map entries with a match in the il PDB
3920     //         will be included, the rest skipped.)
3921     // 
3922     //     * iSeqPointLastUnmatched != -1 iff it equals a prior entry in the IL PDB that
3923     //         we skipped over because it could not be exactly matched to an entry in the
3924     //         il-to-native map.  In such a case, it will be considered for a
3925     //         range-match to the next il-to-native map entry
3926     while (iIlNativeMap < m_cIlNativeMap)
3927     {
3928         _ASSERTE (iMapIndexPairs < cMapIndexPairsMax);
3929
3930         // IP addresses that map to "special" places (prolog, epilog, or
3931         // other hidden code), will just map to 0xFeeFee, as per convention
3932         if ((m_rgIlNativeMap[iIlNativeMap].ilOffset == NO_MAPPING) ||
3933             (m_rgIlNativeMap[iIlNativeMap].ilOffset == PROLOG) ||
3934             (m_rgIlNativeMap[iIlNativeMap].ilOffset == EPILOG))
3935         {
3936             rgMapIndexPairs[iMapIndexPairs].m_iIlNativeMap = iIlNativeMap;
3937             rgMapIndexPairs[iMapIndexPairs].m_iSeqPoints = kUnmappedIP;
3938             iMapIndexPairs++;
3939
3940             // If we were remembering a prior unmatched entry in the IL PDB, reset it
3941             iSeqPointLastUnmatched = (ULONG32) -1;
3942
3943             // Advance il-native map, NOT il-source map
3944             iIlNativeMap++;
3945             continue;
3946         }
3947
3948         // Cases below actually look at the IL PDB sequence point, so ensure it's still
3949         // in range; otherwise, we're done.
3950         if (iSeqPoints >= cSeqPointsReturned)
3951             break;
3952
3953         if (m_rgIlNativeMap[iIlNativeMap].ilOffset < m_rgilOffsets[iSeqPoints])
3954         {
3955             // Our cursor over the ilnative map is behind the sourceil
3956             // map
3957             
3958             if (iSeqPointLastUnmatched != (ULONG32) -1)
3959             {
3960                 // Range matching: This ilnative entry is behind our cursor in the
3961                 // sourceil map, but this ilnative entry is also ahead of the previous
3962                 // (unmatched) entry in the sourceil map. So this is a case where the JIT
3963                 // generated sequence points that surround, without matching, that
3964                 // previous entry in the sourceil map. So match to that previous
3965                 // (unmatched) entry in the sourceil map.
3966                 _ASSERTE(m_rgilOffsets[iSeqPointLastUnmatched] < m_rgIlNativeMap[iIlNativeMap].ilOffset);
3967                 rgMapIndexPairs[iMapIndexPairs].m_iIlNativeMap = iIlNativeMap;
3968                 rgMapIndexPairs[iMapIndexPairs].m_iSeqPoints = iSeqPointLastUnmatched;
3969                 iMapIndexPairs++;
3970                 
3971                 // Reset our memory of the last unmatched entry in the IL PDB
3972                 iSeqPointLastUnmatched = (ULONG32) -1;
3973             }
3974                         else if (iMapIndexPairs > 0)
3975                         {
3976                                 DWORD lastMatchedilNativeIndex = rgMapIndexPairs[iMapIndexPairs - 1].m_iIlNativeMap;
3977                                 if (m_rgIlNativeMap[iIlNativeMap].ilOffset == m_rgIlNativeMap[lastMatchedilNativeIndex].ilOffset &&
3978                                         m_rgIlNativeMap[iIlNativeMap].nativeOffset < m_rgIlNativeMap[lastMatchedilNativeIndex].nativeOffset)
3979                                 {
3980                                         rgMapIndexPairs[iMapIndexPairs - 1].m_iIlNativeMap = iIlNativeMap;
3981                                 }
3982
3983                         }
3984             // Go to next ilnative map entry
3985             iIlNativeMap++;
3986             continue;
3987         }
3988
3989         if (m_rgilOffsets[iSeqPoints] < m_rgIlNativeMap[iIlNativeMap].ilOffset)
3990         {
3991             // Our cursor over the ilnative map is ahead of the sourceil
3992             // map, so go to next sourceil map entry.  Remember that we're passing over
3993             // this entry in the sourceil map, in case we choose to match to it later.
3994             if (!fCurSeqPointMatched)
3995             {
3996                 iSeqPointLastUnmatched = iSeqPoints;
3997             }
3998             iSeqPoints++;
3999             fCurSeqPointMatched = FALSE;
4000             continue;
4001         }
4002
4003         // At a match
4004         _ASSERTE(m_rgilOffsets[iSeqPoints] == m_rgIlNativeMap[iIlNativeMap].ilOffset);
4005         rgMapIndexPairs[iMapIndexPairs].m_iIlNativeMap = iIlNativeMap;
4006         rgMapIndexPairs[iMapIndexPairs].m_iSeqPoints = iSeqPoints;
4007         
4008         // If we were remembering a prior unmatched entry in the IL PDB, reset it
4009         iSeqPointLastUnmatched = (ULONG32) -1;
4010         
4011         // Advance il-native map, do not advance il-source map in case the next il-native
4012         // entry matches this current il-source map entry, but remember that this current
4013         // il-source map entry has found an exact match
4014         iMapIndexPairs++;
4015         iIlNativeMap++;
4016         fCurSeqPointMatched = TRUE;
4017     }
4018
4019     ULONG32 cMapIndexPairs = iMapIndexPairs;
4020
4021     // PDB format requires the lines array to be sorted by IP offset
4022     QuickSortMapIndexPairsByNativeOffset sorterByIp(rgMapIndexPairs, cMapIndexPairs, m_rgIlNativeMap, m_cIlNativeMap);
4023     sorterByIp.Sort();
4024
4025     //
4026     // Now that the maps are merged and sorted, determine whether there's a hot/cold
4027     // split, where that split is, and then call WriteLinesSubsection to write out each
4028     // region into its own lines-file subsection
4029     // 
4030
4031     // Find the point where the code got split
4032     ULONG32 iMapIndexPairsFirstEntryInColdSection = cMapIndexPairs;
4033     for (iMapIndexPairs = 0; iMapIndexPairs < cMapIndexPairs; iMapIndexPairs++)
4034     {
4035         DWORD dwNativeOffset = m_rgIlNativeMap[rgMapIndexPairs[iMapIndexPairs].m_iIlNativeMap].nativeOffset;
4036         if (dwNativeOffset >= m_pMethodRegionInfo->hotSize)
4037         {
4038             iMapIndexPairsFirstEntryInColdSection = iMapIndexPairs;
4039             break;
4040         }
4041     }
4042
4043     // Adjust the cold offsets (if any) to be relative to the cold start
4044     for (iMapIndexPairs = iMapIndexPairsFirstEntryInColdSection; iMapIndexPairs < cMapIndexPairs; iMapIndexPairs++)
4045     {
4046         DWORD dwNativeOffset = m_rgIlNativeMap[rgMapIndexPairs[iMapIndexPairs].m_iIlNativeMap].nativeOffset;
4047         _ASSERTE (dwNativeOffset >= m_pMethodRegionInfo->hotSize);
4048
4049         // Adjust offset so it's relative to the cold region start
4050         dwNativeOffset -= DWORD(m_pMethodRegionInfo->hotSize);
4051         _ASSERTE(dwNativeOffset < m_pMethodRegionInfo->coldSize);
4052         m_rgIlNativeMap[rgMapIndexPairs[iMapIndexPairs].m_iIlNativeMap].nativeOffset = dwNativeOffset;
4053     }
4054
4055     // Write out the hot region into its own lines-file subsection
4056     hr = WriteDebugSLinesSubsection(
4057         ULONG32(m_pMethodRegionInfo->hotStartAddress - m_addrCodeSection),
4058         ULONG32(m_pMethodRegionInfo->hotSize),
4059         rgMapIndexPairs,
4060         iMapIndexPairsFirstEntryInColdSection);
4061     if (FAILED(hr))
4062         return hr;
4063     
4064     // If there was a hot/cold split, write a separate lines-file subsection for the cold
4065     // region
4066     if (iMapIndexPairsFirstEntryInColdSection < cMapIndexPairs)
4067     {
4068         hr = WriteDebugSLinesSubsection(
4069             ULONG32(m_pMethodRegionInfo->coldStartAddress - m_addrCodeSection),
4070             ULONG32(m_pMethodRegionInfo->coldSize),
4071             &rgMapIndexPairs[iMapIndexPairsFirstEntryInColdSection],
4072             cMapIndexPairs - iMapIndexPairsFirstEntryInColdSection);
4073         if (FAILED(hr))
4074             return hr;
4075     }
4076
4077     return S_OK;
4078 }
4079
4080 //---------------------------------------------------------------------------------------
4081 //
4082 // Manages the writing of all native-IL subsections requred for a given method. Almost do
4083 // the same thing as NGenMethodLinesPdbWriter::WritePDBData. But we will write the native-IL 
4084 // map this time.  
4085 //
4086
4087 HRESULT NGenMethodLinesPdbWriter::WriteNativeILMapPDBData()
4088 {
4089     STANDARD_VM_CONTRACT;
4090
4091     HRESULT hr;
4092
4093     QuickSortILNativeMapByNativeOffset sorterByNativeOffset(m_rgIlNativeMap, m_cIlNativeMap);
4094     sorterByNativeOffset.Sort();
4095
4096     ULONG32 iIlNativeMap = 0;
4097     ULONG32 ilNativeMapFirstEntryInColdeSection = m_cIlNativeMap;
4098     for (iIlNativeMap = 0; iIlNativeMap < m_cIlNativeMap; iIlNativeMap++)
4099     {
4100         if (m_rgIlNativeMap[iIlNativeMap].nativeOffset >= m_pMethodRegionInfo->hotSize)
4101         {
4102             ilNativeMapFirstEntryInColdeSection = iIlNativeMap;
4103             break;
4104         }
4105     }
4106
4107     NewArrayHolder<ICorDebugInfo::OffsetMapping> coldRgIlNativeMap(new ICorDebugInfo::OffsetMapping[m_cIlNativeMap - ilNativeMapFirstEntryInColdeSection]);
4108     // Adjust the cold offsets (if any) to be relative to the cold start
4109     for (iIlNativeMap = ilNativeMapFirstEntryInColdeSection; iIlNativeMap < m_cIlNativeMap; iIlNativeMap++)
4110     {
4111         DWORD dwNativeOffset = m_rgIlNativeMap[iIlNativeMap].nativeOffset;
4112         _ASSERTE(dwNativeOffset >= m_pMethodRegionInfo->hotSize);
4113
4114         // Adjust offset so it's relative to the cold region start
4115         dwNativeOffset -= DWORD(m_pMethodRegionInfo->hotSize);
4116         _ASSERTE(dwNativeOffset < m_pMethodRegionInfo->coldSize);
4117         coldRgIlNativeMap[iIlNativeMap - ilNativeMapFirstEntryInColdeSection].ilOffset = m_rgIlNativeMap[iIlNativeMap].ilOffset;
4118         coldRgIlNativeMap[iIlNativeMap - ilNativeMapFirstEntryInColdeSection].nativeOffset = dwNativeOffset;
4119         coldRgIlNativeMap[iIlNativeMap - ilNativeMapFirstEntryInColdeSection].source = m_rgIlNativeMap[iIlNativeMap].source;
4120     }
4121
4122     // Write out the hot region into its own lines-file subsection
4123     hr = WriteDebugSILLinesSubsection(
4124         ULONG32(m_pMethodRegionInfo->hotStartAddress - m_addrCodeSection),
4125         ULONG32(m_pMethodRegionInfo->hotSize),
4126         m_rgIlNativeMap,
4127         ilNativeMapFirstEntryInColdeSection);
4128     if (FAILED(hr))
4129         return hr;
4130
4131     // If there was a hot/cold split, write a separate lines-file subsection for the cold
4132     // region
4133     if (ilNativeMapFirstEntryInColdeSection < m_cIlNativeMap)
4134     {
4135         hr = WriteDebugSILLinesSubsection(
4136             ULONG32(m_pMethodRegionInfo->coldStartAddress - m_addrCodeSection),
4137             ULONG32(m_pMethodRegionInfo->coldSize),
4138             coldRgIlNativeMap,
4139             m_cIlNativeMap - ilNativeMapFirstEntryInColdeSection);
4140         if (FAILED(hr))
4141             return hr;
4142     }
4143
4144     return S_OK;
4145 }
4146
4147
4148 //---------------------------------------------------------------------------------------
4149 //
4150 // Helper called by NGenMethodLinesPdbWriter::WriteDebugSLinesSubsection and 
4151 // NGenMethodLinesPdbWriter::WriteDebugSILLinesSubsection to initial the DEBUG_S*_LINE 
4152 // subsection headers.
4153 //
4154 // Arguments:
4155 //      * ulCodeStartOffset - Offset relative to the code section, or where this region
4156 //          of code begins
4157 //      * type - the subsection's type
4158 //      * lineSize - how many lines mapping the subsection will have.
4159 //      * cbCode - Size in bytes of this region of code
4160 //      * ppSubSectHeader -  output value which returns the intialed CV_DebugSLinesHeader_t struct pointer.
4161 //      * ppLinesHeader - output value which returns the initialed CV_DebugSLinesHeader_t struct pointer.
4162 //      * ppbLinesSubsectionCur - output value which points to the address right after the DebugSLinesHeader
4163 //
4164 // Return Value:
4165 //      * Pointer which points the staring address of the SubSection.
4166 //
4167
4168 LPBYTE NGenMethodLinesPdbWriter::InitDebugLinesHeaderSection(
4169     DEBUG_S_SUBSECTION_TYPE type,
4170     ULONG32 ulCodeStartOffset,
4171     ULONG32 cbCode,
4172     ULONG32 lineSize,
4173     CV_DebugSSubsectionHeader_t **ppSubSectHeader /*out*/,
4174     CV_DebugSLinesHeader_t ** ppLinesHeader /*out*/,
4175     LPBYTE * ppbLinesSubsectionCur /*out*/)
4176 {
4177     STANDARD_VM_CONTRACT;
4178
4179     UINT64 cbLinesSubsectionEstimate =
4180         sizeof(DWORD) +
4181         sizeof(CV_DebugSSubsectionHeader_t) +
4182         sizeof(CV_DebugSLinesHeader_t) +
4183         // Worst case: assume each sequence point will require its own
4184         // CV_DebugSLinesFileBlockHeader_t
4185         (lineSize * (sizeof(CV_DebugSLinesFileBlockHeader_t) + sizeof(CV_Line_t)));
4186     if (!FitsIn<ULONG32>(cbLinesSubsectionEstimate))
4187     {
4188         return NULL;
4189     }
4190
4191     LPBYTE rgbLinesSubsection = new BYTE[ULONG32(cbLinesSubsectionEstimate)];
4192     LPBYTE pbLinesSubsectionCur = rgbLinesSubsection;
4193
4194     // * (1) DWORD = CV_SIGNATURE_C13 -- the usual subsection signature DWORD
4195     *((DWORD *)pbLinesSubsectionCur) = CV_SIGNATURE_C13;
4196     pbLinesSubsectionCur += sizeof(DWORD);
4197
4198     // * (2) CV_DebugSSubsectionHeader_t
4199     CV_DebugSSubsectionHeader_t * pSubSectHeader = (CV_DebugSSubsectionHeader_t *)pbLinesSubsectionCur;
4200     memset(pSubSectHeader, 0, sizeof(*pSubSectHeader));
4201     pSubSectHeader->type = type;
4202     *ppSubSectHeader = pSubSectHeader;
4203     // pSubSectHeader->cblen to be filled in later once we know the size
4204     pbLinesSubsectionCur += sizeof(*pSubSectHeader);
4205
4206     // * (3) CV_DebugSLinesHeader_t
4207     CV_DebugSLinesHeader_t * pLinesHeader = (CV_DebugSLinesHeader_t *)pbLinesSubsectionCur;
4208     memset(pLinesHeader, 0, sizeof(*pLinesHeader));
4209     pLinesHeader->offCon = ulCodeStartOffset;
4210     pLinesHeader->segCon = m_iCodeSection;
4211     pLinesHeader->flags = 0;   // 0 means line info, but not column info, is included
4212     pLinesHeader->cbCon = cbCode;
4213     *ppLinesHeader = pLinesHeader;
4214     pbLinesSubsectionCur += sizeof(*pLinesHeader);
4215     *ppbLinesSubsectionCur = pbLinesSubsectionCur;
4216     return rgbLinesSubsection;
4217 }
4218
4219 //---------------------------------------------------------------------------------------
4220 //
4221 // Helper called by NGenMethodLinesPdbWriter::WritePDBData to do the actual PDB writing of a single
4222 // lines-subsection.  This is called once for the hot region, and once for the cold
4223 // region, of a given method that has been split.  That means you get two
4224 // lines-subsections for split methods.
4225 //
4226 // Arguments:
4227 //      * ulCodeStartOffset - Offset relative to the code section, or where this region
4228 //          of code begins
4229 //      * cbCode - Size in bytes of this region of code
4230 //      * rgMapIndexPairs - Array of indices forming the merged data from the JIT
4231 //          Manager's IL-to-native map and the IL PDB's IL-to-source map.  It is assumed
4232 //          that this array has indices sorted such that the native offsets increase
4233 //      * cMapIndexPairs - Size in entries of above array.
4234 //
4235 // Assumptions:
4236 //      rgMapIndexPairs must be sorted in order of nativeOffset, i.e.,
4237 //      m_rgIlNativeMap[rgMapIndexPairs[i].m_iIlNativeMap].nativeOffset increases with i.
4238 //
4239
4240 HRESULT NGenMethodLinesPdbWriter::WriteDebugSLinesSubsection(
4241     ULONG32 ulCodeStartOffset,
4242     ULONG32 cbCode,
4243     MapIndexPair * rgMapIndexPairs,
4244     ULONG32 cMapIndexPairs)
4245 {
4246     STANDARD_VM_CONTRACT;
4247
4248     // The lines subsection of the PDB (i.e., "DEBUG_S_LINES"), is a blob consisting of a
4249     // few structs stacked one after the other:
4250     // 
4251     // * (1) DWORD = CV_SIGNATURE_C13 -- the usual subsection signature DWORD
4252     // * (2) CV_DebugSSubsectionHeader_t -- the usual subsection header, with type =
4253     //     DEBUG_S_LINES
4254     // * (3) CV_DebugSLinesHeader_t -- a single header for the entire subsection.  Its
4255     //     purpose is to specify the native function being described, and to specify the
4256     //     size of the variable-sized "blocks" that follow
4257     // * (4) CV_DebugSLinesFileBlockHeader_t -- For each block, you get one of these.  A
4258     //     block is defined by a set of sequence points that map to the same source
4259     //     file.  While iterating through the offsets, we need to define new blocks
4260     //     whenever the source file changes.  In C#, this typically only happens when
4261     //     you advance to (or away from) an unmapped IP (0xFeeFee).
4262     // * (5) CV_Line_t (Line array entries) -- For each block, you get several line
4263     //     array entries, one entry for the beginning of each sequence point.
4264
4265     HRESULT hr;
4266
4267
4268     CV_DebugSSubsectionHeader_t * pSubSectHeader = NULL;
4269     CV_DebugSLinesHeader_t * pLinesHeader = NULL;
4270     CV_DebugSLinesFileBlockHeader_t * LinesFileBlockHeader = NULL;
4271
4272     // the InitDebugLinesHeaderSection will help us taking care of 
4273     // * (1) DWORD = CV_SIGNATURE_C13
4274     // * (2) CV_DebugSSubsectionHeader_t 
4275     // * (3) CV_DebugSLinesHeader_t 
4276     LPBYTE pbLinesSubsectionCur;
4277     LPBYTE prgbLinesSubsection = InitDebugLinesHeaderSection(
4278         DEBUG_S_LINES,
4279         ulCodeStartOffset,
4280         cbCode,
4281         cMapIndexPairs,
4282         &pSubSectHeader,
4283         &pLinesHeader,
4284         &pbLinesSubsectionCur);
4285
4286     if (pbLinesSubsectionCur == NULL)
4287     {
4288         return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
4289     }
4290
4291     NewArrayHolder<BYTE> rgbLinesSubsection(prgbLinesSubsection);
4292
4293     // The loop below takes care of
4294     //     * (4) CV_DebugSLinesFileBlockHeader_t
4295     //     * (5) CV_Line_t (Line array entries)
4296     //
4297     BOOL fAtLeastOneBlockWritten = FALSE;
4298     CV_DebugSLinesFileBlockHeader_t * pLinesFileBlockHeader = NULL;
4299     CV_Line_t * pLineCur = NULL;
4300         CV_Line_t * pLinePrev = NULL;
4301     CV_Line_t * pLineBlockStart = NULL;
4302     BOOL fBeginNewBlock = TRUE;
4303     ULONG32 iSeqPointsPrev = (ULONG32) -1;
4304     DWORD dwNativeOffsetPrev = (DWORD) -1;
4305     DWORD ilOffsetPrev = (DWORD) -1;
4306     WCHAR wszURLPrev[MAX_LONGPATH];
4307     memset(&wszURLPrev, 0, sizeof(wszURLPrev));
4308     LPBYTE pbEnd = NULL;
4309
4310     for (ULONG32 iMapIndexPairs=0; iMapIndexPairs < cMapIndexPairs; iMapIndexPairs++)
4311     {
4312         ULONG32 iSeqPoints = rgMapIndexPairs[iMapIndexPairs].m_iSeqPoints;
4313         ULONG32 iIlNativeMap = rgMapIndexPairs[iMapIndexPairs].m_iIlNativeMap;
4314
4315         // Sometimes the JIT manager will give us duplicate IPs in the IL-to-native
4316         // offset mapping. PDB format frowns on that. Since rgMapIndexPairs is being
4317         // iterated in native offset order, it's easy to find these dupes right now, and
4318         // skip all but the first map containing a given IP offset.
4319         if (pLinePrev != NULL && m_rgIlNativeMap[iIlNativeMap].nativeOffset == pLinePrev->offset)
4320         {
4321                         if (ilOffsetPrev == kUnmappedIP)
4322                         {
4323                                 // if the previous IL offset is kUnmappedIP, then we should rewrite it. 
4324                                 pLineCur = pLinePrev;
4325                         }
4326                         else if (iSeqPoints != kUnmappedIP &&
4327                                 m_rgilOffsets[iSeqPoints] < ilOffsetPrev)
4328                         {
4329                                 pLineCur = pLinePrev;
4330                         }
4331                         else
4332                         {
4333                                 // Found a native offset dupe, ignore the current map entry
4334                                 continue;
4335                         }
4336         }
4337
4338         if ((iSeqPoints != kUnmappedIP) && (iSeqPoints != iSeqPointsPrev))
4339         {
4340             // This is the first iteration where we're looking at this iSeqPoints.  So
4341             // check whether the document name has changed on us.  If it has, that means
4342             // we need to start a new block.
4343             WCHAR wszURL[MAX_LONGPATH];
4344             ULONG32 cchURL;
4345             hr = m_rgpDocs[iSeqPoints]->GetURL(_countof(wszURL), &cchURL, wszURL);
4346             if (FAILED(hr))
4347             {
4348                 // Skip function if IL PDB has data missing
4349                 return S_OK;
4350             }
4351
4352             // wszURL is the best we have for a unique identifier of documents.  See
4353             // whether the previous document's URL is different
4354             if (_wcsicmp(wszURL, wszURLPrev) != 0)
4355             {
4356                 // New document.  Update wszURLPrev, and remember that we need to start a
4357                 // new file block
4358                 if (wcscpy_s(wszURLPrev, _countof(wszURLPrev), wszURL) != 0)
4359                 {
4360                     continue;
4361                 }
4362                 fBeginNewBlock = TRUE;
4363             }
4364
4365             iSeqPointsPrev = iSeqPoints;
4366         }
4367         if (fBeginNewBlock)
4368         {
4369             // We've determined that we need to start a new block. So perform fixups
4370             // against the previous block (if any) first
4371             if (FinalizeLinesFileBlock(pLinesFileBlockHeader, pLineBlockStart, pLineCur))
4372             {
4373                 fAtLeastOneBlockWritten = TRUE;
4374             }
4375             else if (pLinesFileBlockHeader != NULL)
4376             {
4377                 // Previous block had no usable data.  So rewind back to the previous
4378                 // block header, and we'll start there with the next block
4379                 pbLinesSubsectionCur = LPBYTE(pLinesFileBlockHeader);
4380                 pLineCur = (CV_Line_t *) pbLinesSubsectionCur;
4381             }
4382
4383             // Now get the info we'll need for the next block
4384             char szURL[MAX_LONGPATH];
4385             int cbWritten = WideCharToMultiByte(
4386                 CP_UTF8,
4387                 0,                                      // dwFlags
4388                 wszURLPrev,
4389                 -1,                                     // i.e., input is NULL-terminated
4390                 szURL,                                  // output: UTF8 string starts here
4391                 _countof(szURL),                        // Available space
4392                 NULL,                                   // lpDefaultChar
4393                 NULL                                    // lpUsedDefaultChar
4394                 );
4395             if (cbWritten == 0)
4396                 continue;
4397
4398             DocNameOffsets docNameOffsets;
4399             BOOL fExists = m_pDocNameToOffsetMap->Lookup(szURL, &docNameOffsets);
4400             if (fExists)
4401             {
4402                 _ASSERTE(docNameOffsets.m_dwChksumTableOffset != (ULONG32) -1);
4403             }
4404             else
4405             {
4406                 // We may get back an invalid document in the 0xFeeFee case (i.e., a
4407                 // sequence point that intentionally doesn't map back to a publicly
4408                 // available source code line).  In that case, we'll use the bogus cksum
4409                 // offset of -1 for now, and verify we're in the 0xFeeFee case later on
4410                 // (see code:NGenMethodLinesPdbWriter::FinalizeLinesFileBlock).
4411                 _ASSERTE(szURL[0] == '\0');
4412                 _ASSERTE(docNameOffsets.m_dwChksumTableOffset == (ULONG32) -1);
4413             }
4414
4415
4416             // * (4) CV_DebugSLinesFileBlockHeader_t
4417             if (pLineCur == NULL)
4418             {
4419                 // First lines file block, so begin the block header immediately after the
4420                 // subsection headers
4421                 pLinesFileBlockHeader = (CV_DebugSLinesFileBlockHeader_t *) pbLinesSubsectionCur;
4422             }
4423             else
4424             {
4425                 // We've had blocks before this one, so add this block at our current
4426                 // location in the blob
4427                 pLinesFileBlockHeader = (CV_DebugSLinesFileBlockHeader_t *) pLineCur;
4428             }
4429             
4430             // PDB structure sizes guarantee this is the case, though their docs are
4431             // explicit that each lines-file block header must be 4-byte aligned.
4432             _ASSERTE(IS_ALIGNED(pLinesFileBlockHeader, 4));
4433
4434             memset(pLinesFileBlockHeader, 0, sizeof(*pLinesFileBlockHeader));
4435             pLinesFileBlockHeader->offFile = docNameOffsets.m_dwChksumTableOffset;
4436             // pLinesFileBlockHeader->nLines to be filled in when block is complete
4437             // pLinesFileBlockHeader->cbBlock to be filled in when block is complete
4438
4439             pLineCur = (CV_Line_t *) (pLinesFileBlockHeader + 1);
4440             pLineBlockStart = pLineCur;
4441             fBeginNewBlock = FALSE;
4442         }
4443
4444
4445         pLineCur->offset = m_rgIlNativeMap[iIlNativeMap].nativeOffset;
4446         pLineCur->linenumStart = 
4447             (iSeqPoints == kUnmappedIP) ? 
4448             kUnmappedIP : 
4449             m_rgnLineStarts[iSeqPoints];
4450         pLineCur->deltaLineEnd = 0;
4451         pLineCur->fStatement = 1;
4452                 ilOffsetPrev = (iSeqPoints == kUnmappedIP) ? kUnmappedIP : m_rgilOffsets[iSeqPoints];
4453                 pLinePrev = pLineCur;
4454         pLineCur++;
4455     }       // for (ULONG32 iMapIndexPairs=0; iMapIndexPairs < cMapIndexPairs; iMapIndexPairs++)
4456
4457     if (pLineCur == NULL)
4458     {
4459         // There were no lines data for this function, so don't write anything
4460         return S_OK;
4461     }
4462
4463     // Perform fixups against the last block we wrote
4464     if (FinalizeLinesFileBlock(pLinesFileBlockHeader, pLineBlockStart, pLineCur))
4465         fAtLeastOneBlockWritten = TRUE;
4466
4467     if (!fAtLeastOneBlockWritten)
4468     {
4469         // There were no valid blocks to write for this function, so don't bother
4470         // calling PDB writing API.  No problem.
4471         return S_OK;
4472     }
4473
4474     // Now that we know pSubSectHeader->cbLen, fill it in
4475     pSubSectHeader->cbLen = CV_off32_t(LPBYTE(pLineCur) - LPBYTE(pLinesHeader));
4476
4477     // Subsection is now filled out, so add it.
4478     hr = m_pWriter->ModAddSymbols(
4479         m_pMod,
4480         rgbLinesSubsection, 
4481
4482         // The size we pass here is the size of the entire byte array that we pass in.
4483         int(LPBYTE(pLineCur) - rgbLinesSubsection));
4484
4485     if (FAILED(hr))
4486         return hr;
4487
4488     return S_OK;
4489 }
4490
4491 //---------------------------------------------------------------------------------------
4492 //
4493 // Helper called by NGenMethodLinesPdbWriter::WriteNativeILMapPDBData to do the actual PDB writing of a single
4494 // lines-subsection.  This is called once for the hot region, and once for the cold
4495 // region, of a given method that has been split.  That means you get two
4496 // lines-subsections for split methods.
4497 //
4498 // Arguments:
4499 //      * ulCodeStartOffset - Offset relative to the code section, or where this region
4500 //          of code begins
4501 //      * cbCode - Size in bytes of this region of code
4502 //      * rgIlNativeMap - IL to Native map array.
4503 //      * rgILNativeMapAdjustSize - the number of elements we need to read in rgILNativeMap.
4504 //
4505
4506 HRESULT NGenMethodLinesPdbWriter::WriteDebugSILLinesSubsection(
4507     ULONG32 ulCodeStartOffset,
4508     ULONG32 cbCode,
4509     ICorDebugInfo::OffsetMapping * rgIlNativeMap,
4510     ULONG32 rgILNativeMapAdjustSize)
4511 {
4512     STANDARD_VM_CONTRACT;
4513
4514     // The lines subsection of the PDB (i.e., "DEBUG_S_IL_LINES"), is a blob consisting of a
4515     // few structs stacked one after the other:
4516     // 
4517     // * (1) DWORD = CV_SIGNATURE_C13 -- the usual subsection signature DWORD
4518     // * (2) CV_DebugSSubsectionHeader_t -- the usual subsection header, with type =
4519     //     DEBUG_S_LINES
4520     // * (3) CV_DebugSLinesHeader_t -- a single header for the entire subsection.  Its
4521     //     purpose is to specify the native function being described, and to specify the
4522     //     size of the variable-sized "blocks" that follow
4523     // * (4) CV_DebugSLinesFileBlockHeader_t -- For each block, you get one of these.  A
4524     //     block is defined by a set of sequence points that map to the same source
4525     //     file.  While iterating through the offsets, we need to define new blocks
4526     //     whenever the source file changes.  In C#, this typically only happens when
4527     //     you advance to (or away from) an unmapped IP (0xFeeFee).
4528     // * (5) CV_Line_t (Line array entries) -- For each block, you get several line
4529     //     array entries, one entry for the beginning of each sequence point.
4530
4531     HRESULT hr;
4532
4533     CV_DebugSSubsectionHeader_t * pSubSectHeader = NULL;
4534     CV_DebugSLinesHeader_t * pLinesHeader = NULL;
4535     CV_DebugSLinesFileBlockHeader_t * pLinesFileBlockHeader = NULL;
4536
4537     // the InitDebugLinesHeaderSection will help us taking care of 
4538     // * (1) DWORD = CV_SIGNATURE_C13
4539     // * (2) CV_DebugSSubsectionHeader_t 
4540     // * (3) CV_DebugSLinesHeader_t 
4541     LPBYTE pbLinesSubsectionCur;
4542     LPBYTE prgbLinesSubsection = InitDebugLinesHeaderSection(
4543         DEBUG_S_IL_LINES,
4544         ulCodeStartOffset,
4545         cbCode,
4546         rgILNativeMapAdjustSize,
4547         &pSubSectHeader,
4548         &pLinesHeader,
4549         &pbLinesSubsectionCur);
4550
4551     if (prgbLinesSubsection == NULL)
4552     {
4553         return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
4554     }
4555
4556     NewArrayHolder<BYTE> rgbLinesSubsection(prgbLinesSubsection);
4557
4558     // The loop below takes care of
4559     //     * (4) CV_DebugSLinesFileBlockHeader_t
4560     //     * (5) CV_Line_t (Line array entries)
4561     //
4562     CV_Line_t * pLineCur = NULL;
4563     CV_Line_t * pLineBlockStart = NULL;
4564     BOOL fBeginNewBlock = TRUE;
4565     LPBYTE pbEnd = NULL;
4566
4567     pLinesFileBlockHeader = (CV_DebugSLinesFileBlockHeader_t *)pbLinesSubsectionCur;
4568     // PDB structure sizes guarantee this is the case, though their docs are
4569     // explicit that each lines-file block header must be 4-byte aligned.
4570     _ASSERTE(IS_ALIGNED(pLinesFileBlockHeader, 4));
4571
4572     memset(pLinesFileBlockHeader, 0, sizeof(*pLinesFileBlockHeader));
4573     char szURL[MAX_PATH];
4574     int cbWritten = WideCharToMultiByte(
4575         CP_UTF8,
4576         0,                                      // dwFlags
4577         UNKNOWN_SOURCE_FILE_PATH,
4578         -1,                                     // i.e., input is NULL-terminated
4579         szURL,                                  // output: UTF8 string starts here
4580         _countof(szURL),                        // Available space
4581         NULL,                                   // lpDefaultChar
4582         NULL                                    // lpUsedDefaultChar
4583         );
4584     _ASSERTE(cbWritten > 0);
4585     DocNameOffsets docNameOffsets;
4586     m_pDocNameToOffsetMap->Lookup(szURL, &docNameOffsets);
4587     pLinesFileBlockHeader->offFile = docNameOffsets.m_dwChksumTableOffset;
4588     // pLinesFileBlockHeader->nLines to be filled in when block is complete
4589     // pLinesFileBlockHeader->cbBlock to be filled in when block is complete
4590
4591     pLineCur = (CV_Line_t *)(pLinesFileBlockHeader + 1);
4592     pLineBlockStart = pLineCur;
4593     CV_Line_t * pLinePrev = NULL;
4594
4595     for (ULONG32 iINativeMap = 0;iINativeMap < rgILNativeMapAdjustSize; iINativeMap++)
4596     {
4597         if ((rgIlNativeMap[iINativeMap].ilOffset == NO_MAPPING) ||
4598             (rgIlNativeMap[iINativeMap].ilOffset == PROLOG) ||
4599             (rgIlNativeMap[iINativeMap].ilOffset == EPILOG))
4600         {
4601             rgIlNativeMap[iINativeMap].ilOffset = kUnmappedIP;
4602         }
4603
4604         // Sometimes the JIT manager will give us duplicate native offset in the IL-to-native
4605         // offset mapping. PDB format frowns on that. Since rgMapIndexPairs is being
4606         // iterated in native offset order, it's easy to find these dupes right now, and
4607         // skip all but the first map containing a given IP offset.
4608         if (pLinePrev != NULL &&
4609             rgIlNativeMap[iINativeMap].nativeOffset == pLinePrev->offset)
4610         {
4611             if (pLinePrev->linenumStart == kUnmappedIP)
4612             {
4613                 // if the previous IL offset is kUnmappedIP, then we should rewrite it. 
4614                 pLineCur = pLinePrev;
4615             }
4616             else if (rgIlNativeMap[iINativeMap].ilOffset != kUnmappedIP &&
4617                 rgIlNativeMap[iINativeMap].ilOffset < pLinePrev->linenumStart)
4618             {
4619                 pLineCur = pLinePrev;
4620             }
4621             else
4622             {
4623                 // Found a native offset dupe, ignore the current map entry
4624                 continue;
4625             }
4626         }
4627
4628         pLineCur->linenumStart = rgIlNativeMap[iINativeMap].ilOffset;
4629
4630         pLineCur->offset = rgIlNativeMap[iINativeMap].nativeOffset;
4631         pLineCur->fStatement = 1;
4632         pLineCur->deltaLineEnd = 0;
4633         pLinePrev = pLineCur;
4634         pLineCur++;
4635     }
4636
4637     if (pLineCur == NULL)
4638     {
4639         // There were no lines data for this function, so don't write anything
4640         return S_OK;
4641     }
4642
4643     if (!FinalizeLinesFileBlock(pLinesFileBlockHeader, pLineBlockStart, pLineCur
4644 #ifdef _DEBUG
4645         , true
4646 #endif
4647         ))
4648     {
4649         return S_OK;
4650     }
4651
4652     // Now that we know pSubSectHeader->cbLen, fill it in
4653     pSubSectHeader->cbLen = CV_off32_t(LPBYTE(pLineCur) - LPBYTE(pLinesHeader));
4654
4655     // Subsection is now filled out, so add it.
4656     hr = m_pWriter->ModAddSymbols(
4657         m_pMod,
4658         rgbLinesSubsection,
4659
4660         // The size we pass here is the size of the entire byte array that we pass in.
4661         long(LPBYTE(pLineCur) - rgbLinesSubsection));
4662
4663     if (FAILED(hr))
4664         return hr;
4665
4666     return S_OK;
4667 }
4668
4669 //---------------------------------------------------------------------------------------
4670 //
4671 // Performs final fixups on the last lines-file block we completed, specifically writing
4672 // in the size of the block, now that it's known.  Also responsible for determining
4673 // whether there is even any data to write in the first place.
4674 //
4675 // Arguments:
4676 //      * pLinesFileBlockHeader - lines-file block header to write to
4677 //      * pLineBlockStart - First CV_Line_t * of this block
4678 //      * pLineBlockAfterEnd - Last CV_Line_t * of this block plus 1
4679 //
4680 // Return Value:
4681 //      * TRUE: lines-file block was nonempty, and is now finalized
4682 //      * FALSE: lines-file block was empty, and caller should toss it out.
4683 //
4684
4685 BOOL NGenMethodLinesPdbWriter::FinalizeLinesFileBlock(
4686     CV_DebugSLinesFileBlockHeader_t * pLinesFileBlockHeader, 
4687     CV_Line_t * pLineBlockStart,
4688     CV_Line_t * pLineBlockAfterEnd
4689 #ifdef _DEBUG
4690   , BOOL ignorekUnmappedIPCheck
4691 #endif
4692     )
4693 {
4694     LIMITED_METHOD_CONTRACT;
4695
4696     if (pLinesFileBlockHeader == NULL)
4697     {
4698         // If a given function has no sequence points at all, pLinesFileBlockHeader can
4699         // be NULL.  No problem
4700         return FALSE;
4701     }
4702
4703     if (pLineBlockStart == pLineBlockAfterEnd)
4704     {
4705         // If we start a lines file block and then realize that there are no entries
4706         // (i.e., no valid sequence points to map), then we end up with an empty block. 
4707         // No problem, just skip the block.
4708         return FALSE;
4709     }
4710
4711     _ASSERTE(pLineBlockStart != NULL);
4712     _ASSERTE(pLineBlockAfterEnd != NULL);
4713     _ASSERTE(pLineBlockAfterEnd > pLineBlockStart);
4714
4715     if (pLinesFileBlockHeader->offFile == (ULONG32) -1)
4716     {
4717         // The file offset we set for this block is invalid. This should be due to the
4718         // 0xFeeFee case (i.e., sequence points that intentionally don't map back to a
4719         // publicly available source code line). Fix up the offset to be valid (point it
4720         // at the first file), but the offset will generally be ignored by the PDB
4721         // reader.
4722 #ifdef _DEBUG
4723     {
4724         if (!ignorekUnmappedIPCheck)
4725         {
4726             for (CV_Line_t * pLineCur = pLineBlockStart; pLineCur < pLineBlockAfterEnd; pLineCur++)
4727             {
4728                 _ASSERTE(pLineCur->linenumStart == kUnmappedIP);
4729             }
4730         }
4731     }
4732 #endif // _DEBUG
4733         pLinesFileBlockHeader->offFile = 0;
4734     }
4735
4736     // Now that we know the size of the block, finish filling out the lines file block
4737     // header
4738     pLinesFileBlockHeader->nLines = CV_off32_t(pLineBlockAfterEnd - pLineBlockStart);
4739     pLinesFileBlockHeader->cbBlock = pLinesFileBlockHeader->nLines * sizeof(CV_Line_t);
4740     
4741     return TRUE;
4742 }
4743 #endif // NO_NGENPDB
4744 #if defined(FEATURE_PERFMAP) || !defined(NO_NGENPDB)
4745 HRESULT __stdcall CreatePdb(CORINFO_ASSEMBLY_HANDLE hAssembly, BSTR pNativeImagePath, BSTR pPdbPath, BOOL pdbLines, BSTR pManagedPdbSearchPath, LPCWSTR pDiasymreaderPath)
4746 {
4747     STANDARD_VM_CONTRACT;
4748
4749     Assembly *pAssembly = reinterpret_cast<Assembly *>(hAssembly);
4750     _ASSERTE(pAssembly);
4751     _ASSERTE(pNativeImagePath);
4752     _ASSERTE(pPdbPath);
4753
4754 #if !defined(NO_NGENPDB)
4755     NGenPdbWriter pdbWriter(
4756         pNativeImagePath, 
4757         pPdbPath, 
4758         pdbLines ? kPDBLines : 0,
4759         pManagedPdbSearchPath);
4760     IfFailThrow(pdbWriter.Load(pDiasymreaderPath));
4761 #elif defined(FEATURE_PERFMAP)
4762     NativeImagePerfMap perfMap(pAssembly, pPdbPath);
4763 #endif
4764
4765     ModuleIterator moduleIterator = pAssembly->IterateModules();
4766     Module *pModule = NULL;
4767     BOOL fAtLeastOneNativeModuleFound = FALSE;
4768     
4769     while (moduleIterator.Next()) 
4770     {
4771         pModule = moduleIterator.GetModule();
4772
4773         if (pModule->HasNativeImage() || pModule->IsReadyToRun())
4774         {
4775 #if !defined(NO_NGENPDB)
4776             IfFailThrow(pdbWriter.WritePDBDataForModule(pModule));
4777 #elif defined(FEATURE_PERFMAP)
4778             perfMap.LogDataForModule(pModule);
4779 #endif
4780             fAtLeastOneNativeModuleFound = TRUE;
4781         }
4782     }
4783
4784     if (!fAtLeastOneNativeModuleFound)
4785     {
4786         GetSvcLogger()->Printf(
4787             W("Loaded image '%s' (for input file '%s') is not a native image.\n"),
4788             pAssembly->GetManifestFile()->GetPath().GetUnicode(),
4789             pNativeImagePath);
4790         return CORDBG_E_NO_IMAGE_AVAILABLE;
4791     }
4792
4793     GetSvcLogger()->Printf(
4794 #if !defined(NO_NGENPDB)
4795         W("Successfully generated PDB for native assembly '%s'.\n"),
4796 #elif defined(FEATURE_PERFMAP)
4797         W("Successfully generated perfmap for native assembly '%s'.\n"),
4798 #endif
4799         pNativeImagePath);
4800
4801     return S_OK;
4802 }
4803 #else
4804 HRESULT __stdcall CreatePdb(CORINFO_ASSEMBLY_HANDLE hAssembly, BSTR pNativeImagePath, BSTR pPdbPath, BOOL pdbLines, BSTR pManagedPdbSearchPath, LPCWSTR pDiasymreaderPath)
4805 {
4806     return E_NOTIMPL;
4807 }
4808 #endif // defined(FEATURE_PERFMAP) || !defined(NO_NGENPDB)
4809
4810 // End of PDB writing code
4811 // ----------------------------------------------------------------------------
4812
4813
4814 BOOL CEEPreloader::CanPrerestoreEmbedClassHandle(CORINFO_CLASS_HANDLE handle)
4815 {
4816     STANDARD_VM_CONTRACT;
4817
4818     if (IsReadyToRunCompilation())
4819         return FALSE;
4820
4821     TypeHandle th(handle);
4822
4823     return m_image->CanPrerestoreEagerBindToTypeHandle(th, NULL);
4824 }
4825
4826 BOOL CEEPreloader::CanPrerestoreEmbedMethodHandle(CORINFO_METHOD_HANDLE handle)
4827 {
4828     STANDARD_VM_CONTRACT;
4829
4830     if (IsReadyToRunCompilation())
4831         return FALSE;
4832
4833     MethodDesc *pMD = (MethodDesc*) handle;
4834
4835     return m_image->CanPrerestoreEagerBindToMethodDesc(pMD, NULL);
4836 }
4837
4838 ICorCompilePreloader * CEECompileInfo::PreloadModule(CORINFO_MODULE_HANDLE module,
4839                                                 ICorCompileDataStore *pData,
4840                                                 CorProfileData       *profileData)
4841 {
4842     STANDARD_VM_CONTRACT;
4843
4844     NewHolder<CEEPreloader> pPreloader(new CEEPreloader((Module *) module, pData));
4845     
4846     COOPERATIVE_TRANSITION_BEGIN();
4847
4848     if (PartialNGenStressPercentage() == 0)
4849     {
4850         pPreloader->Preload(profileData);
4851     }
4852
4853     COOPERATIVE_TRANSITION_END();
4854
4855     return pPreloader.Extract();
4856 }
4857
4858 void CEECompileInfo::SetAssemblyHardBindList(
4859     __in_ecount( cHardBindList )
4860         LPWSTR *pHardBindList,
4861     DWORD  cHardBindList)
4862 {
4863     STANDARD_VM_CONTRACT;
4864
4865 }
4866
4867 HRESULT CEECompileInfo::SetVerboseLevel(
4868          IN  VerboseLevel            level)
4869 {
4870     LIMITED_METHOD_CONTRACT;
4871     HRESULT hr = S_OK;
4872     g_CorCompileVerboseLevel = level;
4873     return hr;
4874 }
4875
4876 //
4877 // Preloader:
4878 //
4879 CEEPreloader::CEEPreloader(Module *pModule,
4880              ICorCompileDataStore *pData)
4881     : m_pData(pData)
4882 {
4883     m_image = new DataImage(pModule, this);
4884
4885     CONSISTENCY_CHECK(pModule == GetAppDomain()->ToCompilationDomain()->GetTargetModule());
4886
4887     GetAppDomain()->ToCompilationDomain()->SetTargetImage(m_image, this);
4888
4889     m_methodCompileLimit = pModule->GetMDImport()->GetCountWithTokenKind(mdtMethodDef) * 10;
4890
4891 #ifdef FEATURE_FULL_NGEN
4892     m_fSpeculativeTriage = FALSE;
4893     m_fDictionariesPopulated = FALSE;
4894 #endif
4895 }
4896
4897 CEEPreloader::~CEEPreloader()
4898 {
4899     WRAPPER_NO_CONTRACT;
4900     delete m_image;
4901 }
4902
4903 void CEEPreloader::Preload(CorProfileData * profileData)
4904 {
4905     STANDARD_VM_CONTRACT;
4906
4907     bool doNothingNgen = false;
4908 #ifdef _DEBUG
4909     static ConfigDWORD fDoNothingNGen;
4910     doNothingNgen = !!fDoNothingNGen.val(CLRConfig::INTERNAL_ZapDoNothing);
4911 #endif
4912
4913     if (!doNothingNgen)
4914     {
4915         m_image->GetModule()->SetProfileData(profileData);
4916         m_image->GetModule()->ExpandAll(m_image);
4917     }
4918
4919     // Triage all items created by initial expansion. 
4920     // We will try to accept all items created by initial expansion. 
4921     TriageForZap(TRUE);
4922 }
4923
4924 //
4925 // ICorCompilerPreloader
4926 //
4927
4928 DWORD CEEPreloader::MapMethodEntryPoint(CORINFO_METHOD_HANDLE handle)
4929 {
4930     STANDARD_VM_CONTRACT;
4931
4932     MethodDesc *pMD = GetMethod(handle);
4933     Precode * pPrecode = pMD->GetSavedPrecode(m_image);
4934
4935     return m_image->GetRVA(pPrecode);
4936 }
4937
4938 DWORD CEEPreloader::MapClassHandle(CORINFO_CLASS_HANDLE handle)
4939 {
4940     STANDARD_VM_CONTRACT;
4941
4942     TypeHandle th = TypeHandle::FromPtr(handle);
4943     if (th.IsTypeDesc())
4944         return m_image->GetRVA(th.AsTypeDesc()) | 2;
4945     else
4946         return m_image->GetRVA(th.AsMethodTable());
4947 }
4948
4949 DWORD CEEPreloader::MapMethodHandle(CORINFO_METHOD_HANDLE handle)
4950 {
4951     STANDARD_VM_CONTRACT;
4952
4953     return m_image->GetRVA(handle);
4954 }
4955
4956 DWORD CEEPreloader::MapFieldHandle(CORINFO_FIELD_HANDLE handle)
4957 {
4958     STANDARD_VM_CONTRACT;
4959
4960     return m_image->GetRVA(handle);
4961 }
4962
4963 DWORD CEEPreloader::MapAddressOfPInvokeFixup(CORINFO_METHOD_HANDLE handle)
4964 {
4965     STANDARD_VM_CONTRACT;
4966
4967     MethodDesc *pMD = GetMethod(handle);
4968
4969     _ASSERTE(pMD->IsNDirect());
4970     NDirectWriteableData * pMDWriteableData = ((NDirectMethodDesc *)pMD)->GetWriteableData();
4971
4972     return m_image->GetRVA(pMDWriteableData) + offsetof(NDirectWriteableData, m_pNDirectTarget);
4973 }
4974
4975 DWORD CEEPreloader::MapGenericHandle(CORINFO_GENERIC_HANDLE handle)
4976 {
4977     STANDARD_VM_CONTRACT;
4978
4979     return m_image->GetRVA(handle);
4980 }
4981
4982 DWORD CEEPreloader::MapModuleIDHandle(CORINFO_MODULE_HANDLE handle)
4983 {
4984     STANDARD_VM_CONTRACT;
4985
4986     return m_image->GetRVA(handle) + (DWORD)Module::GetOffsetOfModuleID();
4987 }
4988
4989 CORINFO_METHOD_HANDLE CEEPreloader::NextUncompiledMethod()
4990 {
4991     STANDARD_VM_CONTRACT;
4992
4993     // If we have run out of methods to compile, ensure that we have code for all methods
4994     // that we are about to save.
4995     if (m_uncompiledMethods.GetCount() == 0)
4996     {
4997 #ifdef FEATURE_FULL_NGEN
4998         if (!m_fSpeculativeTriage)
4999         {
5000             // We take one shot at smarter elimination of speculative instantiations
5001             // that are guaranteed to be found in other modules
5002             TriageSpeculativeInstantiations();
5003             m_fSpeculativeTriage = TRUE;
5004         }
5005 #endif
5006
5007         if (m_uncompiledMethods.GetCount() == 0)
5008         {
5009 #ifdef FEATURE_FULL_NGEN
5010             if (!m_fDictionariesPopulated)
5011             {
5012                 // Prepopulate dictionaries. Only the first population is done in expansive way.
5013                 m_image->GetModule()->PrepopulateDictionaries(m_image, FALSE);
5014                 m_fDictionariesPopulated = TRUE;
5015             }
5016             else
5017 #endif
5018             {
5019                 // The subsequent populations are done in non-expansive way (won't load new types)
5020                 m_image->GetModule()->PrepopulateDictionaries(m_image, TRUE);
5021             }
5022             
5023             // Make sure that we have generated code for all instantiations that we are going to save
5024             // The new items that we encounter here were most likely side effects of verification or failed inlining,
5025             // so do not try to save them eagerly.
5026             while (TriageForZap(FALSE)) {
5027                 // Loop as long as new types are added
5028             }
5029         }
5030     }
5031
5032     // Take next uncompiled method
5033     COUNT_T count = m_uncompiledMethods.GetCount();
5034     if (count == 0)
5035         return NULL;
5036
5037     MethodDesc * pMD = m_uncompiledMethods[count - 1];
5038     m_uncompiledMethods.SetCount(count - 1);
5039
5040 #ifdef _DEBUG 
5041     if (LoggingOn(LF_ZAP, LL_INFO10000))
5042     {
5043         StackSString methodString;
5044         TypeString::AppendMethodDebug(methodString, pMD);
5045
5046         LOG((LF_ZAP, LL_INFO10000, "CEEPreloader::NextUncompiledMethod: %S\n", methodString.GetUnicode()));
5047     }
5048 #endif // _DEBUG
5049
5050     return (CORINFO_METHOD_HANDLE) pMD;
5051 }
5052
5053 void CEEPreloader::AddMethodToTransitiveClosureOfInstantiations(CORINFO_METHOD_HANDLE handle)
5054 {
5055     STANDARD_VM_CONTRACT;
5056
5057     TriageMethodForZap(GetMethod(handle), TRUE);
5058 }
5059
5060 BOOL CEEPreloader::IsMethodInTransitiveClosureOfInstantiations(CORINFO_METHOD_HANDLE handle)
5061 {
5062     STANDARD_VM_CONTRACT;
5063
5064     MethodDesc *pMD = GetMethod(handle);
5065
5066     return (m_acceptedMethods.Lookup(pMD) != NULL) && (m_rejectedMethods.Lookup(pMD) == NULL);
5067 }
5068
5069 BOOL CEEPreloader::IsTypeInTransitiveClosureOfInstantiations(CORINFO_CLASS_HANDLE handle)
5070 {
5071     STANDARD_VM_CONTRACT;
5072
5073     TypeHandle th = (TypeHandle) handle;
5074
5075     return (m_acceptedTypes.Lookup(th) != NULL) && (m_rejectedTypes.Lookup(th) == NULL);
5076 }
5077
5078 void CEEPreloader::MethodReferencedByCompiledCode(CORINFO_METHOD_HANDLE handle)
5079 {
5080     STANDARD_VM_CONTRACT;
5081
5082 #ifndef FEATURE_FULL_NGEN // Unreferenced methods
5083     //
5084     // Keep track of methods that are actually referenced by the code. We use this information 
5085     // to avoid generating code for unreferenced methods not visible outside the assembly.
5086     // These methods are very unlikely to be ever used at runtime because of they only ever be 
5087     // called via private reflection.
5088     //
5089     MethodDesc *pMD = GetMethod(handle);
5090
5091     const CompileMethodEntry * pEntry = m_compileMethodsHash.LookupPtr(pMD);
5092     if (pEntry != NULL)
5093     {
5094         if (pEntry->fReferenced)
5095             return;
5096         const_cast<CompileMethodEntry *>(pEntry)->fReferenced = true;
5097
5098         if (pEntry->fScheduled)
5099             return;        
5100         AppendUncompiledMethod(pMD);
5101     }
5102     else
5103     {
5104         CompileMethodEntry entry;
5105         entry.pMD = pMD;
5106         entry.fReferenced = true;
5107         entry.fScheduled = false;
5108         m_compileMethodsHash.Add(entry);
5109     }
5110
5111     if (pMD->IsWrapperStub())
5112         MethodReferencedByCompiledCode((CORINFO_METHOD_HANDLE)pMD->GetWrappedMethodDesc());
5113 #endif // FEATURE_FULL_NGEN
5114 }
5115
5116 BOOL CEEPreloader::IsUncompiledMethod(CORINFO_METHOD_HANDLE handle)
5117 {
5118     STANDARD_VM_CONTRACT;
5119
5120     MethodDesc *pMD = GetMethod(handle);
5121
5122 #ifndef FEATURE_FULL_NGEN // Unreferenced methods
5123     const CompileMethodEntry * pEntry = m_compileMethodsHash.LookupPtr(pMD);
5124     return (pEntry != NULL) && (pEntry->fScheduled || !pEntry->fReferenced);
5125 #else
5126     return m_compileMethodsHash.LookupPtr(pMD) != NULL;
5127 #endif
5128 }
5129
5130 static bool IsTypeAccessibleOutsideItsAssembly(TypeHandle th)
5131 {
5132     STANDARD_VM_CONTRACT;
5133
5134     if (th.IsTypeDesc())
5135     {
5136         if (th.AsTypeDesc()->HasTypeParam())
5137             return IsTypeAccessibleOutsideItsAssembly(th.AsTypeDesc()->GetTypeParam());
5138
5139         return true;
5140     }
5141
5142     MethodTable * pMT = th.AsMethodTable();
5143
5144     if (pMT == g_pCanonMethodTableClass)
5145         return true;
5146
5147     switch (pMT->GetClass()->GetProtection())
5148     {
5149     case tdPublic:
5150         break;
5151     case tdNestedPublic:
5152     case tdNestedFamily:
5153     case tdNestedFamORAssem:
5154         {
5155             MethodTable * pMTEnclosing = pMT->LoadEnclosingMethodTable();
5156             if (pMTEnclosing == NULL)
5157                 return false;
5158             if (!IsTypeAccessibleOutsideItsAssembly(pMTEnclosing))
5159                 return false;
5160         }
5161         break;
5162
5163     default:
5164         return false;
5165     }
5166
5167     if (pMT->HasInstantiation())
5168     {
5169         Instantiation instantiation = pMT->GetInstantiation();
5170         for (DWORD i = 0; i < instantiation.GetNumArgs(); i++)
5171         {
5172             if (!IsTypeAccessibleOutsideItsAssembly(instantiation[i]))
5173                 return false;
5174         }
5175     }
5176
5177     return true;
5178 }
5179
5180 static bool IsMethodAccessibleOutsideItsAssembly(MethodDesc * pMD)
5181 {
5182     STANDARD_VM_CONTRACT;
5183
5184     // Note that this ignores unrestricted friend access. This friend access allowed attribute can be used to 
5185     // prevent methods from getting trimmed if necessary.
5186     if (pMD->GetMDImport()->GetCustomAttributeByName(pMD->GetMemberDef(), FRIEND_ACCESS_ALLOWED_ATTRIBUTE_TYPE, NULL, NULL) == S_OK)
5187         return true;
5188
5189     switch (pMD->GetAttrs() & mdMemberAccessMask)
5190     {
5191     case mdFamily:
5192     case mdFamORAssem:
5193     case mdPublic:
5194         break;
5195
5196     default:
5197         return false;
5198     }
5199
5200     if (!IsTypeAccessibleOutsideItsAssembly(pMD->GetMethodTable()))
5201         return false;
5202
5203     if (pMD->HasMethodInstantiation())
5204     {
5205         Instantiation instantiation = pMD->GetMethodInstantiation();
5206         for (DWORD i = 0; i < instantiation.GetNumArgs(); i++)
5207         {
5208             if (!IsTypeAccessibleOutsideItsAssembly(instantiation[i]))
5209                 return false;
5210         }
5211     }
5212
5213     return true;
5214 }
5215
5216 static bool IsMethodCallableOutsideItsAssembly(MethodDesc * pMD)
5217 {
5218     STANDARD_VM_CONTRACT;
5219
5220     // Virtual methods can be called via interfaces, etc. We would need to do
5221     // more analysis to trim them. For now, assume that they can be referenced outside this assembly.
5222     if (pMD->IsVirtual())
5223         return true;
5224
5225     // Class constructors are often used with reflection. Always generate code for them.
5226     if (pMD->IsClassConstructorOrCtor())
5227         return true;
5228
5229     if (IsMethodAccessibleOutsideItsAssembly(pMD))
5230         return true;
5231
5232     return false;
5233 }
5234
5235 BOOL IsGenericTooDeeplyNested(TypeHandle t);
5236 void CEEPreloader::AddToUncompiledMethods(MethodDesc *pMD, BOOL fForStubs)
5237 {
5238     STANDARD_VM_CONTRACT;
5239
5240     // TriageTypeForZap() and TriageMethodForZap() should ensure this.
5241     _ASSERTE(m_image->GetModule() == pMD->GetLoaderModule());
5242
5243     if (!fForStubs)
5244     {
5245         if (!pMD->IsIL())
5246             return;
5247
5248         if (!pMD->MayHaveNativeCode() && !pMD->IsWrapperStub())
5249             return;
5250     }
5251
5252     // If it's already been compiled, don't add it to the set of uncompiled methods
5253     if (m_image->GetCodeAddress(pMD) != NULL)
5254         return;
5255     
5256     // If it's already in the queue to be compiled don't add it again
5257     const CompileMethodEntry * pEntry = m_compileMethodsHash.LookupPtr(pMD);
5258
5259 #ifndef FEATURE_FULL_NGEN // Unreferenced methods
5260    if (pEntry != NULL)
5261     {
5262         if (pEntry->fScheduled)
5263             return;
5264
5265         if (!pEntry->fReferenced)
5266             return;
5267
5268         const_cast<CompileMethodEntry *>(pEntry)->fScheduled = true;
5269     }
5270     else
5271     {
5272         // The unreferenced methods optimization works for generic methods and methods on generic types only. 
5273         // Non-generic methods take different path.
5274         //
5275         // It unclear whether it is worth it to enable it for non-generic methods too. The benefit 
5276         // for non-generic methods is small, and the non-generic methods are more likely to be called 
5277         // via private reflection.
5278
5279         bool fSchedule = fForStubs || IsMethodCallableOutsideItsAssembly(pMD);
5280
5281         CompileMethodEntry entry;
5282         entry.pMD = pMD;
5283         entry.fScheduled = fSchedule;
5284         entry.fReferenced = false;
5285         m_compileMethodsHash.Add(entry);
5286
5287         if (!fSchedule)
5288             return;
5289     }
5290 #else // // FEATURE_FULL_NGEN
5291     // Schedule the method for compilation
5292     if (pEntry != NULL)
5293         return;
5294     CompileMethodEntry entry;
5295     entry.pMD = pMD;
5296     m_compileMethodsHash.Add(entry);
5297 #endif // FEATURE_FULL_NGEN
5298
5299     if (pMD->HasMethodInstantiation())
5300     {
5301         Instantiation instantiation = pMD->GetMethodInstantiation();
5302         for (DWORD i = 0; i < instantiation.GetNumArgs(); i++)
5303         {
5304             if (IsGenericTooDeeplyNested(instantiation[i]))
5305                 return;
5306         }
5307     }
5308
5309     // Add it to the set of uncompiled methods
5310     AppendUncompiledMethod(pMD);
5311 }
5312
5313 //
5314 // Used to validate instantiations produced by the production rules before we actually try to instantiate them.
5315 //
5316 static BOOL CanSatisfyConstraints(Instantiation typicalInst, Instantiation candidateInst)
5317 {
5318     STANDARD_VM_CONTRACT;
5319
5320     // The dependency must be of the form C<T> --> D<T>
5321     _ASSERTE(typicalInst.GetNumArgs() == candidateInst.GetNumArgs());
5322     if (typicalInst.GetNumArgs() != candidateInst.GetNumArgs())
5323         return FALSE;
5324
5325     SigTypeContext typeContext(candidateInst, Instantiation());
5326
5327     for (DWORD i = 0; i < candidateInst.GetNumArgs(); i++)
5328     {
5329         TypeHandle thArg = candidateInst[i];
5330
5331         // If this is "__Canon" and we are code sharing then we can't rule out that some
5332         // compatible instantiation may meet the constraints
5333         if (thArg == TypeHandle(g_pCanonMethodTableClass))
5334             continue;
5335
5336         // Otherwise we approximate, and just assume that we have "parametric" constraints
5337         // of the form "T : IComparable<T>" rather than "odd" constraints such as "T : IComparable<string>".
5338         // That is, we assume checking the constraint at the canonical type is sufficient
5339         // to tell us if the constraint holds for all compatible types.
5340         //
5341         // For example of where this does not hold, consider if
5342         //     class C<T>
5343         //     class D<T> where T : IComparable<T>
5344         //     struct Struct<T> : IComparable<string>
5345         // Assume we generate C<Struct<object>>.  Now the constraint
5346         //     Struct<object> : IComparable<object>
5347         // does not hold, so we do not generate the instantiation, even though strictly speaking
5348         // the compatible instantiation C<Struct<string>> will satisfy the constraint
5349         //     Struct<string> : IComparable<string>
5350
5351         TypeVarTypeDesc* tyvar = typicalInst[i].AsGenericVariable();
5352
5353         tyvar->LoadConstraints();
5354
5355         if (!tyvar->SatisfiesConstraints(&typeContext,thArg)) {
5356 #ifdef _DEBUG
5357             /*
5358             // In case we want to know which illegal instantiations we ngen'ed
5359             StackSString candidateInstName;
5360             StackScratchBuffer buffer;
5361             thArg.GetName(candidateInstName);
5362             char output[1024];
5363             _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));
5364             OutputDebugStringA(output);
5365             */
5366 #endif
5367             return FALSE;
5368         }
5369     }
5370
5371     return TRUE;
5372 }
5373
5374
5375 //
5376 // This method has duplicated logic from bcl\system\collections\generic\comparer.cs
5377 //
5378 static void SpecializeComparer(SString& ss, Instantiation& inst)
5379 {
5380     STANDARD_VM_CONTRACT;
5381
5382     if (inst.GetNumArgs() != 1) {
5383         _ASSERTE(!"Improper use of a TypeDependencyAttribute for Comparer");
5384         return;
5385     }
5386
5387     TypeHandle elemTypeHnd = inst[0];
5388
5389     //
5390     // Override the default ObjectComparer for special cases
5391     //
5392     if (elemTypeHnd.CanCastTo(
5393         TypeHandle(MscorlibBinder::GetClass(CLASS__ICOMPARABLEGENERIC)).Instantiate(Instantiation(&elemTypeHnd, 1))))
5394     {
5395         ss.Set(W("System.Collections.Generic.GenericComparer`1"));
5396         return;
5397     }
5398
5399     if (Nullable::IsNullableType(elemTypeHnd))
5400     {
5401         Instantiation nullableInst = elemTypeHnd.AsMethodTable()->GetInstantiation();
5402         if (nullableInst[0].CanCastTo(
5403             TypeHandle(MscorlibBinder::GetClass(CLASS__ICOMPARABLEGENERIC)).Instantiate(nullableInst)))
5404         {
5405             ss.Set(W("System.Collections.Generic.NullableComparer`1"));
5406             inst = nullableInst;
5407             return;
5408         }
5409     }
5410
5411     if (elemTypeHnd.IsEnum())
5412     {
5413         CorElementType et = elemTypeHnd.GetVerifierCorElementType();
5414         if (et == ELEMENT_TYPE_I1 ||
5415             et == ELEMENT_TYPE_I2 ||
5416             et == ELEMENT_TYPE_I4)
5417         {
5418             ss.Set(W("System.Collections.Generic.Int32EnumComparer`1"));
5419             return;
5420         }
5421         if (et == ELEMENT_TYPE_U1 ||
5422             et == ELEMENT_TYPE_U2 ||
5423             et == ELEMENT_TYPE_U4)
5424         {
5425             ss.Set(W("System.Collections.Generic.UInt32EnumComparer`1"));
5426             return;
5427         }
5428         if (et == ELEMENT_TYPE_I8)
5429         {
5430             ss.Set(W("System.Collections.Generic.Int64EnumComparer`1"));
5431             return;
5432         }
5433         if (et == ELEMENT_TYPE_U8)
5434         {
5435             ss.Set(W("System.Collections.Generic.UInt64EnumComparer`1"));
5436             return;
5437         }
5438     }
5439 }
5440
5441 //
5442 // This method has duplicated logic from bcl\system\collections\generic\equalitycomparer.cs
5443 //
5444 static void SpecializeEqualityComparer(SString& ss, Instantiation& inst)
5445 {
5446     STANDARD_VM_CONTRACT;
5447
5448     if (inst.GetNumArgs() != 1) {
5449         _ASSERTE(!"Improper use of a TypeDependencyAttribute for EqualityComparer");
5450         return;
5451     }
5452
5453     TypeHandle elemTypeHnd = inst[0];
5454
5455     //
5456     // Override the default ObjectEqualityComparer for special cases
5457     //
5458     if (elemTypeHnd.CanCastTo(
5459         TypeHandle(MscorlibBinder::GetClass(CLASS__IEQUATABLEGENERIC)).Instantiate(Instantiation(&elemTypeHnd, 1))))
5460     {
5461         ss.Set(W("System.Collections.Generic.GenericEqualityComparer`1"));
5462         return;
5463     }
5464
5465     if (Nullable::IsNullableType(elemTypeHnd))
5466     {
5467         Instantiation nullableInst = elemTypeHnd.AsMethodTable()->GetInstantiation();
5468         if (nullableInst[0].CanCastTo(
5469             TypeHandle(MscorlibBinder::GetClass(CLASS__IEQUATABLEGENERIC)).Instantiate(nullableInst)))
5470         {
5471             ss.Set(W("System.Collections.Generic.NullableEqualityComparer`1"));
5472             inst = nullableInst;
5473             return;
5474         }
5475     }
5476
5477     if (elemTypeHnd.IsEnum())
5478     {
5479         // 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 
5480         // implementation of GetHashCode is more complex than for the other types.
5481         CorElementType et = elemTypeHnd.GetVerifierCorElementType();
5482         if (et == ELEMENT_TYPE_I4 ||
5483             et == ELEMENT_TYPE_U4 ||
5484             et == ELEMENT_TYPE_U2 ||
5485             et == ELEMENT_TYPE_U1)
5486         {
5487             ss.Set(W("System.Collections.Generic.EnumEqualityComparer`1"));
5488             return;
5489         }
5490         else if (et == ELEMENT_TYPE_I2)
5491         {
5492             ss.Set(W("System.Collections.Generic.ShortEnumEqualityComparer`1"));
5493             return;
5494         }
5495         else if (et == ELEMENT_TYPE_I1)
5496         {
5497             ss.Set(W("System.Collections.Generic.SByteEnumEqualityComparer`1"));
5498             return;
5499         }
5500         else if (et == ELEMENT_TYPE_I8 ||
5501                  et == ELEMENT_TYPE_U8)
5502         {
5503             ss.Set(W("System.Collections.Generic.LongEnumEqualityComparer`1"));
5504             return;
5505         }
5506     }
5507 }
5508
5509 #ifdef FEATURE_COMINTEROP
5510 // Instantiation of WinRT types defined in non-WinRT module. This check is required to generate marshaling stubs for
5511 // instantiations of shadow WinRT types like EventHandler<ITracingStatusChangedEventArgs> in mscorlib.
5512 static BOOL IsInstantationOfShadowWinRTType(MethodTable * pMT)
5513 {
5514     STANDARD_VM_CONTRACT;
5515
5516     Instantiation inst = pMT->GetInstantiation();
5517     for (DWORD i = 0; i < inst.GetNumArgs(); i++)
5518     {
5519         TypeHandle th = inst[i];
5520         if (th.IsProjectedFromWinRT() && !th.GetModule()->IsWindowsRuntimeModule())
5521             return TRUE;
5522     }
5523     return FALSE;
5524 }
5525 #endif
5526
5527 void CEEPreloader::ApplyTypeDependencyProductionsForType(TypeHandle t)
5528 {
5529     STANDARD_VM_CONTRACT;
5530
5531     // Only actual types
5532     if (t.IsTypeDesc())
5533         return;
5534
5535     MethodTable * pMT = t.AsMethodTable();
5536
5537     if (!pMT->HasInstantiation() || pMT->ContainsGenericVariables())
5538         return;
5539
5540 #ifdef FEATURE_COMINTEROP
5541     // At run-time, generic redirected interfaces and delegates need matching instantiations
5542     // of other types/methods in order to be marshaled across the interop boundary.
5543     if (m_image->GetModule()->IsWindowsRuntimeModule() || IsInstantationOfShadowWinRTType(pMT))
5544     {
5545         // We only apply WinRT dependencies when compiling .winmd assemblies since redirected
5546         // types are heavily used in non-WinRT code as well and would bloat native images.
5547         if (pMT->IsLegalNonArrayWinRTType())
5548         {
5549             TypeHandle thWinRT;
5550             WinMDAdapter::RedirectedTypeIndex index;
5551             if (WinRTInterfaceRedirector::ResolveRedirectedInterface(pMT, &index))
5552             {
5553                 // redirected interface needs the mscorlib-local definition of the corresponding WinRT type
5554                 MethodTable *pWinRTMT = WinRTInterfaceRedirector::GetWinRTTypeForRedirectedInterfaceIndex(index);
5555                 thWinRT = TypeHandle(pWinRTMT);
5556
5557                 // and matching stub methods
5558                 WORD wNumSlots = pWinRTMT->GetNumVirtuals();
5559                 for (WORD i = 0; i < wNumSlots; i++)
5560                 {
5561                     MethodDesc *pAdapterMD = WinRTInterfaceRedirector::GetStubMethodForRedirectedInterface(
5562                         index,
5563                         i,
5564                         TypeHandle::Interop_NativeToManaged,
5565                         FALSE,
5566                         pMT->GetInstantiation());
5567
5568                     TriageMethodForZap(pAdapterMD, TRUE);
5569                 }
5570             }
5571             if (WinRTDelegateRedirector::ResolveRedirectedDelegate(pMT, &index))
5572             {
5573                 // redirected delegate needs the mscorlib-local definition of the corresponding WinRT type
5574                 thWinRT = TypeHandle(WinRTDelegateRedirector::GetWinRTTypeForRedirectedDelegateIndex(index));
5575             }
5576
5577             if (!thWinRT.IsNull())
5578             {
5579                 thWinRT = thWinRT.Instantiate(pMT->GetInstantiation());
5580                 TriageTypeForZap(thWinRT, TRUE);
5581             }
5582         }
5583     }
5584 #endif // FEATURE_COMINTEROP
5585
5586     pMT = pMT->GetCanonicalMethodTable();
5587
5588     // The TypeDependencyAttribute attribute is currently only allowed on mscorlib types
5589     // Don't even look for the attribute on types in other assemblies.
5590     if(!pMT->GetModule()->IsSystem()) {
5591         return;
5592     }
5593
5594     // Part 1. - check for an NGEN production rule specified by a use of CompilerServices.TypeDependencyAttribute
5595     //  e.g. C<T> --> D<T>
5596     //
5597     // For example, if C<int> is generated then we produce D<int>.
5598     //
5599     // Normally NGEN can detect such productions through the process of compilation, but there are some
5600     // legitimate uses of reflection to generate generic instantiations which NGEN cannot detect.
5601     // In particular typically D<T> will have more constraints than C<T>, e.g.
5602     //     class D<T> where T : IComparable<T>
5603     // Uses of dynamic constraints are an example - consider making a Comparer<T>, where we can have a
5604     // FastComparer<T> where T : IComparable<T>, and the "slow" version checks for the non-generic
5605     // IComparer interface.
5606     // Also, T[] : IList<T>, IReadOnlyList<T>, and both of those interfaces should have a type dependency on SZArrayHelper's generic methods.
5607     //
5608     IMDInternalImport *pImport = pMT->GetMDImport();
5609     HRESULT hr;
5610
5611     _ASSERTE(pImport);
5612     //walk all of the TypeDependencyAttributes
5613     MDEnumHolder hEnum(pImport);
5614     hr = pImport->EnumCustomAttributeByNameInit(pMT->GetCl(),
5615                                                 g_CompilerServicesTypeDependencyAttribute, &hEnum);
5616     if (SUCCEEDED(hr))
5617     {
5618         mdCustomAttribute tkAttribute;
5619         const BYTE *pbAttr;
5620         ULONG cbAttr;
5621
5622         while (pImport->EnumNext(&hEnum, &tkAttribute))
5623         {
5624             //get attribute and validate format
5625             if (FAILED(pImport->GetCustomAttributeAsBlob(
5626                 tkAttribute,
5627                 reinterpret_cast<const void **>(&pbAttr),
5628                 &cbAttr)))
5629             {
5630                 continue;
5631             }
5632
5633             CustomAttributeParser cap(pbAttr, cbAttr);
5634             if (FAILED(cap.SkipProlog()))
5635                 continue;
5636
5637             LPCUTF8 szString;
5638             ULONG   cbString;
5639             if (FAILED(cap.GetNonNullString(&szString, &cbString)))
5640                 continue;
5641
5642             StackSString ss(SString::Utf8, szString, cbString);
5643             Instantiation inst = pMT->GetInstantiation();
5644
5645 #ifndef FEATURE_FULL_NGEN
5646             // Do not expand non-canonical instantiations. They are not that expensive to create at runtime 
5647             // using code:ClassLoader::CreateTypeHandleForNonCanonicalGenericInstantiation if necessary.
5648             if (!ClassLoader::IsCanonicalGenericInstantiation(inst))
5649                 continue;
5650 #endif
5651
5652             if (ss.Equals(W("System.Collections.Generic.ObjectComparer`1")))
5653             {
5654                 SpecializeComparer(ss, inst);
5655             }
5656             else
5657             if (ss.Equals(W("System.Collections.Generic.ObjectEqualityComparer`1")))
5658             {
5659                 SpecializeEqualityComparer(ss, inst);
5660             }
5661
5662             // Try to load the class using its name as a fully qualified name. If that fails,
5663             // then we try to load it in the assembly of the current class.
5664             TypeHandle typicalDepTH = TypeName::GetTypeUsingCASearchRules(ss.GetUnicode(), pMT->GetAssembly());
5665
5666             _ASSERTE(!typicalDepTH.IsNull());
5667             // This attribute is currently only allowed to refer to mscorlib types
5668             _ASSERTE(typicalDepTH.GetModule()->IsSystem());
5669             if (!typicalDepTH.GetModule()->IsSystem())
5670                 continue;
5671
5672             // For IList<T>, ICollection<T>, IEnumerable<T>, IReadOnlyCollection<T> & IReadOnlyList<T>, include SZArrayHelper's
5673             // generic methods (or at least the relevant ones) in the ngen image in 
5674             // case someone casts a T[] to an IList<T> (or ICollection<T> or IEnumerable<T>, etc).
5675             if (MscorlibBinder::IsClass(typicalDepTH.AsMethodTable(), CLASS__SZARRAYHELPER))
5676             {
5677 #ifdef FEATURE_FULL_NGEN
5678                 if (pMT->GetNumGenericArgs() != 1 || !pMT->IsInterface()) {
5679                     _ASSERTE(!"Improper use of a TypeDependencyAttribute for SZArrayHelper");
5680                     continue;
5681                 }
5682                 TypeHandle elemTypeHnd = pMT->GetInstantiation()[0];
5683                 if (elemTypeHnd.IsValueType())
5684                     ApplyTypeDependencyForSZArrayHelper(pMT, elemTypeHnd);
5685 #endif
5686                 continue;
5687             }
5688
5689             _ASSERTE(typicalDepTH.IsTypicalTypeDefinition());
5690             if (!typicalDepTH.IsTypicalTypeDefinition())
5691                 continue;
5692
5693             // It certainly can't be immediately recursive...
5694             _ASSERTE(!typicalDepTH.GetMethodTable()->HasSameTypeDefAs(pMT));
5695
5696             // We want to rule out some cases where we know for sure that the generated type
5697             // won't satisfy its constraints.  However, some generated types may represent
5698             // canonicals in sets of shared instantaitions,
5699
5700             if (CanSatisfyConstraints(typicalDepTH.GetInstantiation(), inst))
5701             {
5702                 TypeHandle instDepTH =
5703                     ClassLoader::LoadGenericInstantiationThrowing(typicalDepTH.GetModule(), typicalDepTH.GetCl(), inst);
5704
5705                 _ASSERTE(!instDepTH.ContainsGenericVariables());
5706                 _ASSERTE(instDepTH.GetNumGenericArgs() == typicalDepTH.GetNumGenericArgs());
5707                 _ASSERTE(instDepTH.GetMethodTable()->HasSameTypeDefAs(typicalDepTH.GetMethodTable()));
5708
5709                 // OK, add the generated type to the dependency set
5710                 TriageTypeForZap(instDepTH, TRUE);
5711             }
5712         }
5713     }
5714 } // CEEPreloader::ApplyTypeDependencyProductionsForType
5715
5716
5717 // Given IEnumerable<Foo>, we want to add System.SZArrayHelper.GetEnumerator<Foo> 
5718 // to the ngen image.  This way we can cast a T[] to an IList<T> and
5719 // use methods on it (from SZArrayHelper) without pulling in the JIT.
5720 // Do the same for ICollection<T>/IReadOnlyCollection<T> and 
5721 // IList<T>/IReadOnlyList<T>, but only add the relevant methods 
5722 // from those interfaces.  
5723 void CEEPreloader::ApplyTypeDependencyForSZArrayHelper(MethodTable * pInterfaceMT, TypeHandle elemTypeHnd)
5724 {
5725     STANDARD_VM_CONTRACT;
5726
5727     _ASSERTE(elemTypeHnd.AsMethodTable()->IsValueType());
5728
5729     // We expect this to only be called for IList<T>/IReadOnlyList<T>, ICollection<T>/IReadOnlyCollection<T>, IEnumerable<T>.
5730     _ASSERTE(pInterfaceMT->IsInterface());
5731     _ASSERTE(pInterfaceMT->GetNumGenericArgs() == 1);
5732
5733     // This is the list of methods that don't throw exceptions on SZArrayHelper.
5734     static const BinderMethodID SZArrayHelperMethodIDs[] = { 
5735         // Read-only methods that are present on both regular and read-only interfaces.
5736         METHOD__SZARRAYHELPER__GETENUMERATOR,
5737         METHOD__SZARRAYHELPER__GET_COUNT,
5738         METHOD__SZARRAYHELPER__GET_ITEM, 
5739         // The rest of the methods is present on regular interfaces only.
5740         METHOD__SZARRAYHELPER__SET_ITEM, 
5741         METHOD__SZARRAYHELPER__COPYTO, 
5742         METHOD__SZARRAYHELPER__INDEXOF,
5743         METHOD__SZARRAYHELPER__CONTAINS };
5744
5745     static const int cReadOnlyMethods = 3;
5746     static const int cAllMethods = 7;
5747
5748     static const BinderMethodID LastMethodOnGenericArrayInterfaces[] = {
5749         METHOD__SZARRAYHELPER__GETENUMERATOR, // Last method of IEnumerable<T>
5750         METHOD__SZARRAYHELPER__REMOVE, // Last method of ICollection<T>.
5751         METHOD__SZARRAYHELPER__REMOVEAT, // Last method of IList<T>
5752     };
5753     
5754     // Assuming the binder ID's are properly laid out in mscorlib.h
5755 #if _DEBUG
5756     for(unsigned int i=0; i < NumItems(LastMethodOnGenericArrayInterfaces) - 1; i++) {
5757         _ASSERTE(LastMethodOnGenericArrayInterfaces[i] < LastMethodOnGenericArrayInterfaces[i+1]);
5758     }
5759 #endif
5760
5761     MethodTable* pExactMT = MscorlibBinder::GetClass(CLASS__SZARRAYHELPER);
5762
5763     // Subtract one from the non-generic IEnumerable that the generic IEnumerable<T>
5764     // inherits from.  
5765     unsigned inheritanceDepth = pInterfaceMT->GetNumInterfaces() - 1;
5766     PREFIX_ASSUME(0 <= inheritanceDepth && inheritanceDepth < NumItems(LastMethodOnGenericArrayInterfaces));
5767     
5768     // Read-only interfaces happen to always have one method
5769     bool fIsReadOnly = pInterfaceMT->GetNumVirtuals() == 1;
5770
5771     for(int i=0; i < (fIsReadOnly ? cReadOnlyMethods : cAllMethods); i++)
5772     {
5773         // Check whether the method applies for this type.
5774         if (SZArrayHelperMethodIDs[i] > LastMethodOnGenericArrayInterfaces[inheritanceDepth])
5775             continue;
5776
5777         MethodDesc * pPrimaryMD = MscorlibBinder::GetMethod(SZArrayHelperMethodIDs[i]);
5778
5779         MethodDesc * pInstantiatedMD = MethodDesc::FindOrCreateAssociatedMethodDesc(pPrimaryMD, 
5780                                            pExactMT, false, Instantiation(&elemTypeHnd, 1), false);
5781
5782         TriageMethodForZap(pInstantiatedMD, true);
5783     }
5784 }
5785
5786
5787 void CEEPreloader::AddTypeToTransitiveClosureOfInstantiations(CORINFO_CLASS_HANDLE handle)
5788 {
5789     STANDARD_VM_CONTRACT;
5790
5791     TriageTypeForZap((TypeHandle) handle, TRUE);
5792 }
5793
5794 const unsigned MAX_ZAP_INSTANTIATION_NESTING = 10;
5795
5796 BOOL IsGenericTooDeeplyNested(TypeHandle t)
5797 {
5798     CONTRACTL
5799     {
5800         NOTHROW;
5801         MODE_ANY;
5802     }
5803     CONTRACTL_END;
5804     //if this type is more than N levels nested deep, do not add it to the
5805     //closure.  Build a queue for a DFS of the depth of instantiation.
5806
5807     //the current index in the queue we're visiting
5808     int currentQueueIdx; //use -1 to indicate that we're done.
5809     //the current generic arg type.
5810     TypeHandle currentVisitingType[MAX_ZAP_INSTANTIATION_NESTING];
5811
5812     //the ordinal in the GetInstantiation for the current type (over [0,
5813     //GetNumGenericArg())
5814     unsigned currentGenericArgEdge[MAX_ZAP_INSTANTIATION_NESTING];
5815
5816     //initialize the DFS.
5817     memset(currentGenericArgEdge, 0, sizeof(currentGenericArgEdge));
5818     currentVisitingType[0] = t;
5819     currentQueueIdx = 0;
5820
5821     while( currentQueueIdx >= 0 )
5822     {
5823         //see if we're done with this node
5824         if( currentVisitingType[currentQueueIdx].GetNumGenericArgs()
5825             <= currentGenericArgEdge[currentQueueIdx] )
5826         {
5827             --currentQueueIdx;
5828         }
5829         else
5830         {
5831             //more edges to visit.  So visit one edge
5832             _ASSERTE(currentGenericArgEdge[currentQueueIdx] < currentVisitingType[currentQueueIdx].GetNumGenericArgs());
5833             TypeHandle current = currentVisitingType[currentQueueIdx].GetInstantiation()[currentGenericArgEdge[currentQueueIdx]];
5834             ++currentGenericArgEdge[currentQueueIdx];
5835             //only value types cause a problem because of "approximate" type
5836             //loading, so only worry about scanning value type arguments.
5837             if( current.HasInstantiation() && current.IsValueType()  )
5838             {
5839                 //new edge.  Make sure there is space in the queue.
5840                 if( (currentQueueIdx + 1) >= (int)NumItems(currentGenericArgEdge) )
5841                 {
5842                     //exceeded the allowable depth.  Stop processing.
5843                     return TRUE;
5844                 }
5845                 else
5846                 {
5847                     ++currentQueueIdx;
5848                     currentGenericArgEdge[currentQueueIdx] = 0;
5849                     currentVisitingType[currentQueueIdx] = current;
5850                 }
5851             }
5852         }
5853     }
5854
5855     return FALSE;
5856 }
5857
5858 void CEEPreloader::TriageTypeForZap(TypeHandle th, BOOL fAcceptIfNotSure, BOOL fExpandDependencies)
5859 {
5860     STANDARD_VM_CONTRACT;
5861
5862     // We care about param types only
5863     if (th.IsTypicalTypeDefinition() && !th.IsTypeDesc())
5864         return;
5865
5866     // We care about types from our module only
5867     if (m_image->GetModule() != th.GetLoaderModule())
5868         return;
5869
5870     // Check if we have decided to accept this type already.
5871     if (m_acceptedTypes.Lookup(th) != NULL)
5872         return;
5873
5874     // Check if we have decided to reject this type already.
5875     if (m_rejectedTypes.Lookup(th) != NULL)
5876         return;
5877
5878     enum { Investigate, Accepted, Rejected } triage = Investigate;
5879
5880     const char * rejectReason = NULL;
5881
5882     // TypeVarTypeDesc are saved via links from code:Module::m_GenericParamToDescMap
5883     if (th.IsGenericVariable())
5884     {
5885         triage = Rejected;
5886         rejectReason = "type is a Generic variable";
5887         goto Done;
5888     }
5889
5890     /* Consider this example:
5891
5892     class A<T> {}
5893     class B<U> : A<U> {}
5894
5895     class C<V> : B<V> 
5896     {
5897         void foo<W>()
5898         {
5899             typeof(C<W>);
5900             typeof(B<A<W>>);
5901
5902             typeof(List<V>);
5903         }
5904     }
5905
5906     The open instantiations can be divided into the following 3 categories:
5907
5908     1. A<T>,  B<U>, A<U>,  C<V>, B<V>, A<V> are open instantiations involving 
5909        ELEMENT_TYPE_VARs that need to be saved in the ngen image.
5910     2. List<V> is an instantiations that also involves ELEMENT_TYPE_VARs.
5911        However, it need not be saved since it will only be needed during the
5912        verification of foo<W>(). 
5913     3. C<W>, A<W>, B<A<W>> are open instantiations involving ELEMENT_TYPE_MVARs 
5914        that need not be saved since they will only be needed during the
5915        verification of foo<W>().
5916
5917     Distinguishing between 1 and 2 requires walking C<V> and determining
5918     which ones are field/parent/interface types required by c<V>. However,
5919     category 3 is easy to detect, and can easily be pruned out. Hence,
5920     we pass in methodTypeVarsOnly=TRUE here.
5921     */
5922     if (th.ContainsGenericVariables(TRUE/*methodTypeVarsOnly*/))
5923     {
5924         triage = Rejected;
5925         rejectReason = "type contains method generic variables";
5926         goto Done;
5927     }
5928
5929     // Filter out weird cases we do not care about.
5930     if (!m_image->GetModule()->GetAvailableParamTypes()->ContainsValue(th))
5931     {
5932         triage = Rejected;
5933         rejectReason = "type is not in the current module";
5934         return;
5935     }
5936
5937     // Reject invalid generic instantiations. They will not be fully loaded
5938     // as they will throw a TypeLoadException before they reach CLASS_LOAD_LEVEL_FINAL.
5939     if (!th.IsFullyLoaded())
5940     {
5941         // This may load new types. May load new types.
5942         ClassLoader::TryEnsureLoaded(th);
5943
5944         if (!th.IsFullyLoaded())
5945         {
5946             triage = Rejected;
5947             rejectReason = "type could not be fully loaded, possibly because it does not satisfy its constraints";
5948             goto Done;
5949         }
5950     }
5951
5952     // Do not save any types containing generic class parameters from another module
5953     Module *pOpenModule;
5954     pOpenModule = th.GetDefiningModuleForOpenType();
5955     if (pOpenModule != NULL && pOpenModule != m_image->GetModule())
5956     {
5957         triage = Rejected;
5958         rejectReason = "type contains generic variables from another module";
5959         goto Done;
5960     }
5961
5962     // Always store items in their preferred zap module even if we are not sure
5963     if (Module::GetPreferredZapModuleForTypeHandle(th) == m_image->GetModule())
5964     {
5965         triage = Accepted;
5966         goto Done;
5967     }
5968
5969 #ifdef FEATURE_FULL_NGEN
5970     // Only save arrays and other param types in their preferred zap modules, 
5971     // i.e. never duplicate them.
5972     if (th.IsTypeDesc() || th.IsArrayType())
5973     {
5974         triage = Rejected;
5975         rejectReason = "type is a TypeDesc";
5976         goto Done;
5977     }
5978
5979     {
5980         // Do not save instantiations found in one of our hardbound dependencies
5981         PtrHashMap::PtrIterator iter = GetAppDomain()->ToCompilationDomain()->IterateHardBoundModules();
5982         for (/**/; !iter.end(); ++iter)
5983         {
5984             Module * hardBoundModule = (Module*)iter.GetValue();
5985             if (hardBoundModule->GetAvailableParamTypes()->ContainsValue(th))
5986             {
5987                 triage = Rejected;
5988                 rejectReason = "type was found in a hardbound dependency";
5989                 goto Done;
5990             }
5991         }
5992     }
5993
5994     // We are not really sure about this type. Accept it only if we have been asked to.
5995     if (fAcceptIfNotSure)
5996     {
5997         if (!m_fSpeculativeTriage)
5998         {
5999             // We will take a look later before we actually start compiling the instantiations
6000             m_speculativeTypes.Append(th);
6001             m_acceptedTypes.Add(th);
6002             return;
6003         }
6004
6005         triage = Accepted;
6006         goto Done;
6007     }
6008 #else
6009     rejectReason = "type is not in the preferred module";
6010     triage = Rejected;
6011 #endif
6012
6013 Done:
6014     switch (triage)
6015     {
6016     case Accepted:
6017         m_acceptedTypes.Add(th);
6018         if (fExpandDependencies)
6019         {
6020             ExpandTypeDependencies(th);
6021         }
6022         break;
6023
6024     case Rejected:
6025
6026         m_rejectedTypes.Add(th);
6027
6028 #ifdef LOGGING
6029         // It is expensive to call th.GetName, only do it when we are actually logging
6030         if (LoggingEnabled())
6031         {
6032             SString typeName;
6033             th.GetName(typeName);
6034             LOG((LF_ZAP, LL_INFO10000, "TriageTypeForZap rejects %S (%08x) because %s\n", 
6035                  typeName.GetUnicode(), th.AsPtr(), rejectReason));
6036         }
6037 #endif
6038         break;
6039
6040     default:
6041         // We have not found a compeling reason to accept or reject the type yet. Maybe next time...
6042         break;
6043     }
6044 }
6045
6046 void CEEPreloader::ExpandTypeDependencies(TypeHandle th)
6047 {
6048     STANDARD_VM_CONTRACT;
6049
6050     if (th.IsTypeDesc())
6051         return;
6052     
6053     MethodTable* pMT = th.AsMethodTable();
6054
6055     if (pMT->IsCanonicalMethodTable())
6056     {
6057         // Cutoff infinite recursion.
6058         if (!IsGenericTooDeeplyNested(th))
6059         {
6060             // Make sure all methods are compiled
6061             // We only want to check the method bodies owned by this type,
6062             // and not any method bodies owned by a parent type, as the
6063             // parent type may not get saved in this ngen image.
6064             MethodTable::IntroducedMethodIterator itr(pMT);
6065             for (/**/; itr.IsValid(); itr.Next())
6066             {
6067                 AddToUncompiledMethods(itr.GetMethodDesc(), FALSE);
6068             }
6069         }
6070     }
6071     else
6072     {
6073         // Make sure canonical method table is saved
6074         TriageTypeForZap(pMT->GetCanonicalMethodTable(), TRUE);
6075     }
6076     
6077     if (pMT->SupportsGenericInterop(TypeHandle::Interop_ManagedToNative))
6078     {
6079         MethodTable::IntroducedMethodIterator itr(pMT->GetCanonicalMethodTable());
6080         for (/**/; itr.IsValid(); itr.Next())
6081         {
6082             MethodDesc *pMD = itr.GetMethodDesc();
6083
6084             if (!pMD->HasMethodInstantiation())
6085             {
6086                 if (pMT->IsInterface() || !pMD->IsSharedByGenericInstantiations())
6087                 {
6088                     pMD = MethodDesc::FindOrCreateAssociatedMethodDesc(
6089                         pMD, 
6090                         pMT, 
6091                         FALSE,              // forceBoxedEntryPoint
6092                         Instantiation(),    // methodInst
6093                         FALSE,              // allowInstParam
6094                         TRUE);              // forceRemotableMethod
6095                 }
6096                 else
6097                 {
6098                     _ASSERTE(pMT->IsDelegate());
6099                     pMD = InstantiatedMethodDesc::FindOrCreateExactClassMethod(pMT, pMD);
6100                 }
6101
6102                 AddToUncompiledMethods(pMD, TRUE);
6103             }
6104         }
6105     }
6106
6107     // Make sure parent type is saved
6108     TriageTypeForZap(pMT->GetParentMethodTable(), TRUE);
6109     
6110     // Make sure all instantiation arguments are saved
6111     Instantiation inst = pMT->GetInstantiation();
6112     for (DWORD iArg = 0; iArg < inst.GetNumArgs(); iArg++)
6113     {
6114         TriageTypeForZap(inst[iArg], TRUE);
6115     }
6116     
6117     // Make sure all interfaces implemeted by the class are saved
6118     MethodTable::InterfaceMapIterator intIterator = pMT->IterateInterfaceMap();
6119     while (intIterator.Next())
6120     {
6121         TriageTypeForZap(intIterator.GetInterface(), TRUE);
6122     }
6123     
6124     // Make sure aprox types for all fields are saved
6125     ApproxFieldDescIterator fdIterator(pMT, ApproxFieldDescIterator::ALL_FIELDS);
6126     FieldDesc* pFD;
6127     while ((pFD = fdIterator.Next()) != NULL)
6128     {
6129         if (pFD->GetFieldType() == ELEMENT_TYPE_VALUETYPE)
6130         {
6131             TriageTypeForZap(pFD->GetFieldTypeHandleThrowing(), TRUE);
6132         }
6133     }
6134     
6135     // Make sure types for all generic static fields are saved
6136     
6137     if (pMT->HasGenericsStaticsInfo())
6138     {
6139         FieldDesc *pGenStaticFields = pMT->GetGenericsStaticFieldDescs();
6140         DWORD nFields = pMT->GetNumStaticFields();
6141         for (DWORD iField = 0; iField < nFields; iField++)
6142         {
6143             FieldDesc* pField = &pGenStaticFields[iField];
6144             if (pField->GetFieldType() == ELEMENT_TYPE_VALUETYPE)
6145             {
6146                 TriageTypeForZap(pField->GetFieldTypeHandleThrowing(), TRUE);
6147             }
6148         }
6149     }
6150     
6151     // Expand type using the custom rules. May load new types.
6152     ApplyTypeDependencyProductionsForType(th);
6153 }
6154
6155 // Triage instantiations of generic methods
6156
6157 void CEEPreloader::TriageMethodForZap(MethodDesc* pMD, BOOL fAcceptIfNotSure, BOOL fExpandDependencies)
6158 {
6159     STANDARD_VM_CONTRACT;
6160
6161     // Submit the method type for triage
6162     TriageTypeForZap(TypeHandle(pMD->GetMethodTable()), fAcceptIfNotSure);
6163
6164     // We care about instantiated methods only
6165     if (pMD->IsTypicalMethodDefinition())
6166         return;
6167
6168     // We care about methods from our module only
6169     if (m_image->GetModule() != pMD->GetLoaderModule())
6170         return;
6171
6172     // Check if we have decided to accept this method already.
6173     if (m_acceptedMethods.Lookup(pMD) != NULL)
6174         return;
6175
6176     // Check if we have decided to reject this method already.
6177     if (m_rejectedMethods.Lookup(pMD) != NULL)
6178         return;
6179
6180     enum { Investigate, Accepted, Rejected } triage = Investigate;
6181
6182     const char * rejectReason = NULL;
6183
6184     // Do not save open methods
6185     if (pMD->ContainsGenericVariables())
6186     {
6187         triage = Rejected;
6188         rejectReason = "method contains method generic variables";
6189         goto Done;
6190     }
6191
6192     // Filter out other weird cases we do not care about.
6193     if (!m_image->GetModule()->GetInstMethodHashTable()->ContainsMethodDesc(pMD))
6194     {
6195         triage = Rejected;
6196         rejectReason = "method is not in the current module";
6197         goto Done;
6198     }
6199
6200     // Always store items in their preferred zap module even if we are not sure
6201     if (Module::GetPreferredZapModuleForMethodDesc(pMD) == m_image->GetModule())
6202     {
6203         triage = Accepted;
6204         goto Done;
6205     }
6206
6207 #ifdef FEATURE_FULL_NGEN
6208     {
6209         // Do not save instantiations found in one of our hardbound dependencies
6210         PtrHashMap::PtrIterator iter = GetAppDomain()->ToCompilationDomain()->IterateHardBoundModules();
6211         for (/**/; !iter.end(); ++iter)
6212         {
6213             Module * hardBoundModule = (Module*)iter.GetValue();
6214             if (hardBoundModule->GetInstMethodHashTable()->ContainsMethodDesc(pMD))
6215             {
6216                 triage = Rejected;
6217                 rejectReason = "method was found in a hardbound dependency";
6218                 goto Done;
6219             }
6220         }
6221     }
6222
6223     // We are not really sure about this method. Accept it only if we have been asked to.
6224     if (fAcceptIfNotSure)
6225     {
6226         // It does not seem worth it to go through extra hoops to eliminate redundant 
6227         // speculative method instatiations from softbound dependencies like we do for types
6228         // if (!m_fSpeculativeTriage)
6229         // {
6230         //    // We will take a look later before we actually start compiling the instantiations
6231         //    ...
6232         // }
6233
6234         triage = Accepted;
6235         goto Done;
6236     }
6237 #else
6238     triage = Rejected;
6239 #endif
6240
6241 Done:
6242     switch (triage)
6243     {
6244     case Accepted:
6245         m_acceptedMethods.Add(pMD);
6246         if (fExpandDependencies)
6247         {
6248             ExpandMethodDependencies(pMD);
6249         }
6250         break;
6251
6252     case Rejected:
6253         m_rejectedMethods.Add(pMD);
6254         LOG((LF_ZAP, LL_INFO10000, "TriageMethodForZap rejects %s (%08x) because %s\n", 
6255             pMD->m_pszDebugMethodName, pMD, rejectReason));
6256         break;
6257
6258     default:
6259         // We have not found a compeling reason to accept or reject the method yet. Maybe next time...
6260         break;
6261     }
6262 }
6263
6264 void CEEPreloader::ExpandMethodDependencies(MethodDesc * pMD)
6265 {
6266     STANDARD_VM_CONTRACT;
6267
6268     AddToUncompiledMethods(pMD, FALSE);
6269
6270     {
6271         // Make sure all instantiation arguments are saved
6272         Instantiation inst = pMD->GetMethodInstantiation();
6273         for (DWORD iArg = 0; iArg < inst.GetNumArgs(); iArg++)
6274         {
6275             TriageTypeForZap(inst[iArg], TRUE);
6276         }
6277     }
6278
6279     // Make sure to add wrapped method desc
6280     if (pMD->IsWrapperStub())
6281         TriageMethodForZap(pMD->GetWrappedMethodDesc(), TRUE);
6282 }
6283
6284 void CEEPreloader::TriageTypeFromSoftBoundModule(TypeHandle th, Module * pSoftBoundModule)
6285 {
6286     STANDARD_VM_CONTRACT;
6287
6288     // We care about types from our module only
6289     if (m_image->GetModule() != th.GetLoaderModule())
6290         return;
6291
6292     // Nothing to do if we have rejected the type already.
6293     if (m_rejectedTypes.Lookup(th) != NULL)
6294         return;
6295
6296     // We make guarantees about types living in its own PZM only
6297     if (Module::GetPreferredZapModuleForTypeHandle(th) != pSoftBoundModule)
6298         return;
6299
6300     // Reject the type - it is guaranteed to be saved in PZM
6301     m_rejectedTypes.Add(th);
6302
6303     if (!th.IsTypeDesc())
6304     {
6305         // Reject the canonical method table if possible.
6306         MethodTable* pMT = th.AsMethodTable();
6307         if (!pMT->IsCanonicalMethodTable())
6308             TriageTypeFromSoftBoundModule(pMT->GetCanonicalMethodTable(), pSoftBoundModule);
6309
6310         // Reject parent method table if possible.
6311         TriageTypeFromSoftBoundModule(pMT->GetParentMethodTable(), pSoftBoundModule);
6312
6313         // Reject all interfaces implemented by the type if possible.
6314         MethodTable::InterfaceMapIterator intIterator = pMT->IterateInterfaceMap();
6315         while (intIterator.Next())
6316         {
6317             TriageTypeFromSoftBoundModule(intIterator.GetInterface(), pSoftBoundModule);
6318         }
6319
6320         // It does not seem worth it to reject the remaining items 
6321         // expanded by CEEPreloader::ExpandTypeDependencies here.
6322     }
6323 }
6324
6325 #ifdef FEATURE_FULL_NGEN
6326 static TypeHandle TryToLoadTypeSpecHelper(Module * pModule, PCCOR_SIGNATURE pSig, ULONG cSig)
6327 {
6328     STANDARD_VM_CONTRACT;
6329
6330     TypeHandle th;
6331
6332     EX_TRY
6333     {
6334         SigPointer p(pSig, cSig);
6335         SigTypeContext typeContext;    // empty context is OK: encoding should not contain type variables.
6336
6337         th = p.GetTypeHandleThrowing(pModule, &typeContext, ClassLoader::DontLoadTypes);
6338     }
6339     EX_CATCH
6340     {
6341     }
6342     EX_END_CATCH(SwallowAllExceptions)
6343
6344     return th;
6345 }
6346
6347 void CEEPreloader::TriageTypeSpecsFromSoftBoundModule(Module * pSoftBoundModule)
6348 {
6349     STANDARD_VM_CONTRACT;
6350
6351     //
6352     // Reject all typespecs that are guranteed to be found in soft bound PZM
6353     //
6354
6355     IMDInternalImport *pInternalImport = pSoftBoundModule->GetMDImport();
6356
6357     HENUMInternalHolder hEnum(pInternalImport);
6358     hEnum.EnumAllInit(mdtTypeSpec);
6359
6360     mdToken tk;
6361     while (pInternalImport->EnumNext(&hEnum, &tk))
6362     {
6363         ULONG cSig;
6364         PCCOR_SIGNATURE pSig;
6365
6366         if (FAILED(pInternalImport->GetTypeSpecFromToken(tk, &pSig, &cSig)))
6367         {
6368             pSig = NULL;
6369             cSig = 0;
6370         }
6371
6372         // Check all types specs that do not contain variables
6373         if (SigPointer(pSig, cSig).IsPolyType(NULL) == hasNoVars)
6374         {
6375             TypeHandle th = TryToLoadTypeSpecHelper(pSoftBoundModule, pSig, cSig);
6376
6377             if (th.IsNull())
6378                 continue;
6379
6380             TriageTypeFromSoftBoundModule(th, pSoftBoundModule);
6381         }
6382     }
6383 }
6384
6385 void CEEPreloader::TriageSpeculativeType(TypeHandle th)
6386 {
6387     STANDARD_VM_CONTRACT;
6388
6389     // Nothing to do if we have rejected the type already
6390     if (m_rejectedTypes.Lookup(th) != NULL)
6391         return;
6392
6393     Module * pPreferredZapModule = Module::GetPreferredZapModuleForTypeHandle(th);
6394     BOOL fHardBoundPreferredZapModule = FALSE;
6395
6396     //
6397     // Even though we have done this check already earlier, do it again here in case we have picked up
6398     // any eager-bound dependency in the meantime
6399     //
6400     // Do not save instantiations found in one of our eager-bound dependencies
6401     PtrHashMap::PtrIterator iter = GetAppDomain()->ToCompilationDomain()->IterateHardBoundModules();
6402     for (/**/; !iter.end(); ++iter)
6403     {
6404         Module * hardBoundModule = (Module*)iter.GetValue();
6405         if (hardBoundModule->GetAvailableParamTypes()->ContainsValue(th))
6406         {
6407             m_rejectedTypes.Add(th);
6408             return;
6409         }
6410
6411         if (hardBoundModule == pPreferredZapModule)
6412         {
6413             fHardBoundPreferredZapModule = TRUE;
6414         }
6415     }
6416
6417     if (!fHardBoundPreferredZapModule && !pPreferredZapModule->AreTypeSpecsTriaged())
6418     {
6419         // Reject all types that are guaranteed to be instantiated in soft bound PZM
6420         TriageTypeSpecsFromSoftBoundModule(pPreferredZapModule);
6421         pPreferredZapModule->SetTypeSpecsTriaged();
6422
6423         if (m_rejectedTypes.Lookup(th) != NULL)
6424             return;
6425     }
6426
6427     // We have to no other option but to accept and expand the type
6428     ExpandTypeDependencies(th);
6429 }
6430
6431 void CEEPreloader::TriageSpeculativeInstantiations()
6432 {
6433     STANDARD_VM_CONTRACT;
6434
6435     // Get definitive triage answer for speculative types that we have run into earlier
6436     // Note that m_speculativeTypes may be growing as this loop runs
6437     for (COUNT_T i = 0; i < m_speculativeTypes.GetCount(); i++)
6438     {
6439         TriageSpeculativeType(m_speculativeTypes[i]);
6440     }
6441
6442     // We are done - the array of speculative types is no longer necessary
6443     m_speculativeTypes.Clear();
6444 }
6445 #endif // FEATURE_FULL_NGEN
6446
6447 BOOL CEEPreloader::TriageForZap(BOOL fAcceptIfNotSure, BOOL fExpandDependencies)
6448 {
6449     STANDARD_VM_CONTRACT;
6450
6451     DWORD dwNumTypes = m_image->GetModule()->GetAvailableParamTypes()->GetCount();
6452     DWORD dwNumMethods = m_image->GetModule()->GetInstMethodHashTable()->GetCount();
6453
6454     // Triage types
6455     {
6456         // Create a local copy in case the new elements are added to the hashtable during population
6457         InlineSArray<TypeHandle, 20> pTypes;
6458
6459         // Make sure the iterator is destroyed before there is a chance of loading new types
6460         {
6461             EETypeHashTable* pTable = m_image->GetModule()->GetAvailableParamTypes();
6462
6463             EETypeHashTable::Iterator it(pTable);
6464             EETypeHashEntry *pEntry;
6465             while (pTable->FindNext(&it, &pEntry))
6466             {
6467                 TypeHandle th = pEntry->GetTypeHandle();
6468                 if (m_acceptedTypes.Lookup(th) == NULL && m_rejectedTypes.Lookup(th) == NULL)
6469                     pTypes.Append(th);
6470             }
6471         }
6472
6473         for(COUNT_T i = 0; i < pTypes.GetCount(); i ++)
6474         {
6475             TriageTypeForZap(pTypes[i], fAcceptIfNotSure, fExpandDependencies);
6476         }
6477     }
6478
6479     // Triage methods
6480     {
6481         // Create a local copy in case the new elements are added to the hashtable during population
6482         InlineSArray<MethodDesc*, 20> pMethods;
6483
6484         // Make sure the iterator is destroyed before there is a chance of loading new methods
6485         {
6486             InstMethodHashTable* pTable = m_image->GetModule()->GetInstMethodHashTable();
6487
6488             InstMethodHashTable::Iterator it(pTable);
6489             InstMethodHashEntry *pEntry;
6490             while (pTable->FindNext(&it, &pEntry))
6491             {
6492                 MethodDesc* pMD = pEntry->GetMethod();
6493                 if (m_acceptedMethods.Lookup(pMD) == NULL && m_rejectedMethods.Lookup(pMD) == NULL)
6494                     pMethods.Append(pMD);
6495             }
6496         }
6497
6498         for(COUNT_T i = 0; i < pMethods.GetCount(); i ++)
6499         {
6500             TriageMethodForZap(pMethods[i], fAcceptIfNotSure, fExpandDependencies);
6501         }
6502     }
6503
6504     // Returns TRUE if new types or methods has been added by the triage
6505     return (dwNumTypes != m_image->GetModule()->GetAvailableParamTypes()->GetCount()) ||
6506            (dwNumMethods != m_image->GetModule()->GetInstMethodHashTable()->GetCount());
6507 }
6508
6509 void CEEPreloader::PrePrepareMethodIfNecessary(CORINFO_METHOD_HANDLE hMethod)
6510 {
6511     STANDARD_VM_CONTRACT;
6512
6513 #ifdef FEATURE_CER
6514     ::PrePrepareMethodIfNecessary(hMethod);
6515 #endif
6516 }
6517
6518 static void SetStubMethodDescOnInteropMethodDesc(MethodDesc* pInteropMD, MethodDesc* pStubMD, bool fReverseStub)
6519 {
6520     CONTRACTL
6521     {
6522         THROWS;
6523         GC_TRIGGERS;
6524         MODE_ANY;
6525
6526         // We store NGENed stubs on these MethodDesc types
6527         PRECONDITION(pInteropMD->IsNDirect() || pInteropMD->IsComPlusCall() || pInteropMD->IsGenericComPlusCall() || pInteropMD->IsEEImpl());
6528     }
6529     CONTRACTL_END;
6530
6531     if (pInteropMD->IsNDirect())
6532     {
6533         _ASSERTE(!fReverseStub);
6534         NDirectMethodDesc* pNMD = (NDirectMethodDesc*)pInteropMD;
6535         pNMD->ndirect.m_pStubMD.SetValue(pStubMD);
6536     }
6537 #ifdef FEATURE_COMINTEROP
6538     else if (pInteropMD->IsComPlusCall() || pInteropMD->IsGenericComPlusCall())
6539     {
6540         _ASSERTE(!fReverseStub);
6541         ComPlusCallInfo *pComInfo = ComPlusCallInfo::FromMethodDesc(pInteropMD);
6542        pComInfo->m_pStubMD.SetValue(pStubMD);
6543     }
6544 #endif // FEATURE_COMINTEROP
6545     else if (pInteropMD->IsEEImpl())
6546     {
6547         DelegateEEClass* pDelegateClass = (DelegateEEClass*)pInteropMD->GetClass();
6548         if (fReverseStub)
6549         {
6550             pDelegateClass->m_pReverseStubMD = pStubMD;
6551         }
6552         else
6553         {
6554 #ifdef FEATURE_COMINTEROP
6555             // We don't currently NGEN both the P/Invoke and WinRT stubs for WinRT delegates.
6556             // If that changes, this function will need an extra parameter to tell what kind
6557             // of stub is being passed.
6558             if (pInteropMD->GetMethodTable()->IsWinRTDelegate())
6559             {
6560                 pDelegateClass->m_pComPlusCallInfo->m_pStubMD.SetValue(pStubMD);
6561             }
6562             else
6563 #endif // FEATURE_COMINTEROP
6564             {
6565                 pDelegateClass->m_pForwardStubMD = pStubMD;
6566             }
6567         }
6568     }
6569     else
6570     {
6571         UNREACHABLE_MSG("unexpected type of MethodDesc");
6572     }
6573 }
6574
6575 MethodDesc * CEEPreloader::CompileMethodStubIfNeeded(
6576         MethodDesc *pMD,
6577         MethodDesc *pStubMD,
6578         ICorCompilePreloader::CORCOMPILE_CompileStubCallback pfnCallback,
6579         LPVOID pCallbackContext)
6580 {
6581     STANDARD_VM_CONTRACT;
6582
6583     LOG((LF_ZAP, LL_INFO10000, "NGEN_ILSTUB: %s::%s -> %s::%s\n",
6584          pMD->m_pszDebugClassName, pMD->m_pszDebugMethodName, pStubMD->m_pszDebugClassName, pStubMD->m_pszDebugMethodName));
6585
6586     // It is possible that the StubMD is a normal method pointed by InteropStubMethodAttribute,
6587     // and in that case we don't need to compile it here
6588     if (pStubMD->IsDynamicMethod())
6589     {
6590         if (!pStubMD->AsDynamicMethodDesc()->GetILStubResolver()->IsCompiled())
6591         {
6592             CORJIT_FLAGS jitFlags = pStubMD->AsDynamicMethodDesc()->GetILStubResolver()->GetJitFlags();
6593
6594             pfnCallback(pCallbackContext, (CORINFO_METHOD_HANDLE)pStubMD, jitFlags);
6595         }
6596
6597 #ifndef FEATURE_FULL_NGEN // Deduplication
6598         const DuplicateMethodEntry * pDuplicate = m_duplicateMethodsHash.LookupPtr(pStubMD);
6599         if (pDuplicate != NULL)
6600             return pDuplicate->pDuplicateMD;
6601 #endif
6602     }
6603
6604 //We do not store ILStubs so if the compilation failed for them
6605 //It does not make sense to keep the MD corresponding to the IL
6606     if (pStubMD->IsILStub() && m_image->GetCodeAddress(pStubMD) == NULL)
6607         pStubMD=NULL;
6608
6609     return pStubMD;
6610 }
6611
6612 void CEEPreloader::GenerateMethodStubs(
6613         CORINFO_METHOD_HANDLE hMethod,
6614         bool                  fNgenProfilerImage,
6615         CORCOMPILE_CompileStubCallback pfnCallback,
6616         LPVOID                pCallbackContext)
6617 {
6618     CONTRACTL
6619     {
6620         STANDARD_VM_CHECK;
6621         PRECONDITION(hMethod != NULL && pfnCallback != NULL);
6622     }
6623     CONTRACTL_END;
6624
6625     MethodDesc* pMD = GetMethod(hMethod);
6626     MethodDesc* pStubMD = NULL;
6627
6628     // Do not generate IL stubs when generating ReadyToRun images
6629     // This prevents versionability concerns around IL stubs exposing internal
6630     // implementation details of the CLR.
6631     if (IsReadyToRunCompilation())
6632         return;
6633
6634     DWORD dwNGenStubFlags = NDIRECTSTUB_FL_NGENEDSTUB;
6635
6636     if (fNgenProfilerImage)
6637         dwNGenStubFlags |= NDIRECTSTUB_FL_NGENEDSTUBFORPROFILING;
6638
6639     //
6640     // Generate IL stubs. If failed, we go through normal NGEN path
6641     // Catch any exceptions that occur when we try to create the IL_STUB
6642     //    
6643     EX_TRY
6644     {
6645         //
6646         // Take care of forward stubs
6647         //            
6648         if (pMD->IsNDirect())
6649         {
6650             NDirectMethodDesc* pNMD = (NDirectMethodDesc*)pMD;
6651             PInvokeStaticSigInfo sigInfo;
6652             NDirect::PopulateNDirectMethodDesc(pNMD, &sigInfo);
6653             pStubMD = NDirect::GetILStubMethodDesc((NDirectMethodDesc*)pMD, &sigInfo, dwNGenStubFlags);
6654         }
6655 #ifdef FEATURE_COMINTEROP
6656         else if (pMD->IsComPlusCall() || pMD->IsGenericComPlusCall())
6657         {
6658             if (MethodNeedsForwardComStub(pMD, m_image))
6659             {
6660                 // Look for predefined IL stubs in forward com interop scenario. 
6661                 // If we've found a stub, that's what we'll use
6662                 DWORD dwStubFlags;
6663                 ComPlusCall::PopulateComPlusCallMethodDesc(pMD, &dwStubFlags);
6664                 if (FAILED(FindPredefinedILStubMethod(pMD, dwStubFlags, &pStubMD)))
6665                 {                    
6666                     pStubMD = ComPlusCall::GetILStubMethodDesc(pMD, dwStubFlags | dwNGenStubFlags);
6667                 }
6668             }
6669         }
6670 #endif // FEATURE_COMINTEROP
6671         else if (pMD->IsEEImpl())
6672         {
6673             MethodTable* pMT = pMD->GetMethodTable();
6674             CONSISTENCY_CHECK(pMT->IsDelegate());
6675
6676             // we can filter out non-WinRT generic delegates right off the top
6677             if (!pMD->HasClassOrMethodInstantiation() || pMT->IsProjectedFromWinRT()
6678 #ifdef FEATURE_COMINTEROP
6679                 || WinRTTypeNameConverter::IsRedirectedType(pMT)
6680 #endif // FEATURE_COMINTEROP
6681                 )
6682             {
6683                 if (COMDelegate::IsDelegateInvokeMethod(pMD)) // build forward stub
6684                 {
6685 #ifdef FEATURE_COMINTEROP
6686                     if ((pMT->IsProjectedFromWinRT() || WinRTTypeNameConverter::IsRedirectedType(pMT)) &&
6687                         (!pMT->HasInstantiation() || pMT->SupportsGenericInterop(TypeHandle::Interop_ManagedToNative))) // filter out shared generics
6688                     {
6689                         // Build the stub for all WinRT delegates, these will definitely be used for interop.
6690                         if (pMT->IsLegalNonArrayWinRTType())
6691                         {
6692                             COMDelegate::PopulateComPlusCallInfo(pMT);
6693                             pStubMD = COMDelegate::GetILStubMethodDesc((EEImplMethodDesc *)pMD, dwNGenStubFlags);
6694                         }
6695                     }
6696                     else
6697 #endif // FEATURE_COMINTEROP
6698                     {
6699                         // Build the stub only if the delegate is decorated with UnmanagedFunctionPointerAttribute.
6700                         // Forward delegate stubs are rare so we require this opt-in to avoid bloating NGEN images.
6701
6702                         if (S_OK == pMT->GetMDImport()->GetCustomAttributeByName(
6703                             pMT->GetCl(), g_UnmanagedFunctionPointerAttribute, NULL, NULL))
6704                         {
6705                             pStubMD = COMDelegate::GetILStubMethodDesc((EEImplMethodDesc *)pMD, dwNGenStubFlags);
6706                         }
6707                     }
6708                 }
6709             }
6710         }
6711
6712         // compile the forward stub
6713         if (pStubMD != NULL)
6714         {
6715             pStubMD = CompileMethodStubIfNeeded(pMD, pStubMD, pfnCallback, pCallbackContext);
6716
6717             // We store the MethodDesc of the Stub on the NDirectMethodDesc/ComPlusCallMethodDesc/DelegateEEClass
6718             // that we can recover the stub MethodDesc at prestub time, do the fixups, and wire up the native code
6719             if (pStubMD != NULL)
6720             {
6721                  SetStubMethodDescOnInteropMethodDesc(pMD, pStubMD, false /* fReverseStub */);
6722                  pStubMD = NULL;
6723             }
6724
6725         }
6726     }
6727     EX_CATCH
6728     {
6729         LOG((LF_ZAP, LL_WARNING, "NGEN_ILSTUB: Generating forward interop stub FAILED: %s::%s\n", pMD->m_pszDebugClassName, pMD->m_pszDebugMethodName));
6730     }
6731     EX_END_CATCH(RethrowTransientExceptions);
6732
6733     //
6734     // Now take care of reverse P/Invoke stubs for delegates
6735     //
6736     if (pMD->IsEEImpl() && COMDelegate::IsDelegateInvokeMethod(pMD))
6737     {
6738         // Reverse P/Invoke is not supported for generic methods and WinRT delegates
6739         if (!pMD->HasClassOrMethodInstantiation() && !pMD->GetMethodTable()->IsProjectedFromWinRT())
6740         {
6741             EX_TRY
6742             {
6743 #ifdef _TARGET_X86_
6744                 // on x86, we call the target directly if Invoke has a no-marshal signature
6745                 if (NDirect::MarshalingRequired(pMD))
6746 #endif // _TARGET_X86_
6747                 {
6748                     PInvokeStaticSigInfo sigInfo(pMD);
6749                     pStubMD = UMThunkMarshInfo::GetILStubMethodDesc(pMD, &sigInfo, NDIRECTSTUB_FL_DELEGATE | dwNGenStubFlags);
6750
6751                     if (pStubMD != NULL)
6752                     {
6753                         // compile the reverse stub
6754                         pStubMD = CompileMethodStubIfNeeded(pMD, pStubMD, pfnCallback, pCallbackContext);
6755
6756                         // We store the MethodDesc of the Stub on the DelegateEEClass
6757                         if (pStubMD != NULL)
6758                         {
6759                             SetStubMethodDescOnInteropMethodDesc(pMD, pStubMD, true /* fReverseStub */);
6760                         }
6761                     }
6762                 }
6763             }
6764             EX_CATCH
6765             {
6766                 LOG((LF_ZAP, LL_WARNING, "NGEN_ILSTUB: Generating reverse interop stub for delegate FAILED: %s::%s\n", pMD->m_pszDebugClassName, pMD->m_pszDebugMethodName));
6767             }
6768             EX_END_CATCH(RethrowTransientExceptions);
6769         }
6770     }
6771
6772 #ifdef FEATURE_COMINTEROP
6773     //
6774     // And finally generate reverse COM stubs
6775     //
6776     EX_TRY
6777     {
6778         // The method doesn't have to have a special type to be exposed to COM, in particular it doesn't
6779         // have to be ComPlusCallMethodDesc. However, it must have certain properties (custom attributes,
6780         // public visibility, etc.)
6781         if (MethodNeedsReverseComStub(pMD))
6782         {
6783             // initialize ComCallMethodDesc
6784             ComCallMethodDesc ccmd;
6785             ComCallMethodDescHolder ccmdHolder(&ccmd);
6786             ccmd.InitMethod(pMD, NULL);
6787
6788             // generate the IL stub
6789             DWORD dwStubFlags;
6790             ComCall::PopulateComCallMethodDesc(&ccmd, &dwStubFlags);
6791             pStubMD = ComCall::GetILStubMethodDesc(pMD, dwStubFlags | dwNGenStubFlags);
6792
6793             if (pStubMD != NULL)
6794             {
6795                 // compile the reverse stub
6796                 pStubMD = CompileMethodStubIfNeeded(pMD, pStubMD, pfnCallback, pCallbackContext);
6797
6798                 if (pStubMD != NULL)
6799                 {
6800                     // store the stub in a hash table on the module
6801                     m_image->GetModule()->GetStubMethodHashTable()->InsertMethodDesc(pMD, pStubMD);
6802                 }
6803             }
6804         }
6805     }
6806     EX_CATCH
6807     {
6808         LOG((LF_ZAP, LL_WARNING, "NGEN_ILSTUB: Generating reverse interop stub FAILED: %s::%s\n", pMD->m_pszDebugClassName, pMD->m_pszDebugMethodName));
6809     }
6810     EX_END_CATCH(RethrowTransientExceptions);
6811 #endif // FEATURE_COMINTEROP
6812 }
6813
6814 bool CEEPreloader::IsDynamicMethod(CORINFO_METHOD_HANDLE hMethod)
6815 {
6816     STANDARD_VM_CONTRACT;
6817
6818     MethodDesc* pMD = GetMethod(hMethod);
6819
6820     if (pMD)
6821     {
6822         return pMD->IsDynamicMethod();
6823     }
6824
6825     return false;
6826 }
6827
6828 // Set method profiling flags for layout of EE datastructures
6829 void CEEPreloader::SetMethodProfilingFlags(CORINFO_METHOD_HANDLE hMethod, DWORD flags)
6830 {
6831     STANDARD_VM_CONTRACT;
6832
6833     _ASSERTE(hMethod != NULL);
6834     _ASSERTE(flags != 0);
6835
6836     return m_image->SetMethodProfilingFlags(GetMethod(hMethod), flags);
6837 }
6838
6839 /*********************************************************************/
6840 // canSkipMethodPreparation: Is there a need for all calls from
6841 // NGEN'd code to a particular MethodDesc to go through DoPrestub,
6842 // depending on the method sematics?  If so return FALSE.
6843 //
6844 // This is used to rule out both ngen-hardbinds and intra-ngen-module
6845 // direct calls.
6846 //
6847 // The cases where direct calls are not allowed are typically where
6848 // a stub must be inserted by DoPrestub (we do not save stubs) or where
6849 // we haven't saved the code for some reason or another, or where fixups
6850 // are required in the MethodDesc.
6851 //
6852 // callerHnd=NULL implies any/unspecified caller.
6853 //
6854 // Note that there may be other requirements for going through the prestub
6855 // which vary based on the scenario. These need to be handled separately
6856
6857 bool CEEPreloader::CanSkipMethodPreparation (
6858         CORINFO_METHOD_HANDLE   callerHnd,
6859         CORINFO_METHOD_HANDLE   calleeHnd,
6860         CorInfoIndirectCallReason *pReason,
6861         CORINFO_ACCESS_FLAGS    accessFlags/*=CORINFO_ACCESS_ANY*/)
6862 {
6863     STANDARD_VM_CONTRACT;
6864
6865     bool result = false;
6866
6867     COOPERATIVE_TRANSITION_BEGIN();
6868
6869     MethodDesc *  calleeMD    = (MethodDesc *)calleeHnd;
6870     MethodDesc *  callerMD    = (MethodDesc *)callerHnd;
6871
6872     {
6873         result = calleeMD->CanSkipDoPrestub(callerMD, pReason, accessFlags);
6874     }
6875
6876     COOPERATIVE_TRANSITION_END();
6877
6878     return result;
6879 }
6880
6881 CORINFO_METHOD_HANDLE CEEPreloader::LookupMethodDef(mdMethodDef token)
6882 {
6883     STANDARD_VM_CONTRACT;
6884
6885     MethodDesc *pMD = MemberLoader::GetMethodDescFromMethodDef(
6886                                      m_image->GetModule(),
6887                                      token,
6888                                      FALSE);
6889
6890     if (IsReadyToRunCompilation() && pMD->HasClassOrMethodInstantiation())
6891     {
6892         _ASSERTE(IsCompilationProcess() && pMD->GetModule_NoLogging() == GetAppDomain()->ToCompilationDomain()->GetTargetModule());
6893     }
6894
6895     pMD = pMD->FindOrCreateTypicalSharedInstantiation();
6896
6897     return CORINFO_METHOD_HANDLE(pMD);
6898 }
6899
6900 CorCompileILRegion CEEPreloader::GetILRegion(mdMethodDef token)
6901 {
6902     STANDARD_VM_CONTRACT;
6903
6904     // Since we are running managed code during NGen the inlining hint may be 
6905     // changing underneeth us as the code is JITed. We need to prevent the inlining
6906     // hints from changing once we start to use them to place IL in the image.
6907     g_pCEECompileInfo->DisableCachingOfInliningHints();
6908
6909     // Default if there is something completely wrong, e.g. the type failed to load.
6910     // We may need the IL at runtime.
6911     CorCompileILRegion region = CORCOMPILE_ILREGION_WARM;
6912
6913     EX_TRY
6914     {
6915         MethodDesc *pMD = m_image->GetModule()->LookupMethodDef(token);
6916
6917         if (pMD == NULL || !pMD->GetMethodTable()->IsFullyLoaded())
6918         {
6919             // Something is completely wrong - use the default
6920         }
6921         else
6922         if (m_image->IsStored(pMD))
6923         {
6924             if (pMD->IsNotInline())
6925             {
6926                 if (pMD->HasClassOrMethodInstantiation())
6927                 {
6928                     region = CORCOMPILE_ILREGION_GENERICS;
6929                 }
6930                 else
6931                 {
6932                     region = CORCOMPILE_ILREGION_COLD;
6933                 }
6934             }
6935             else
6936             if (Security::MethodIsVisibleOutsideItsAssembly(pMD))
6937             {
6938                 // We are inlining only leaf methods, except for mscorlib. Thus we can assume that only methods
6939                 // visible outside its assembly are likely to be inlined.
6940                 region = CORCOMPILE_ILREGION_INLINEABLE;
6941             }
6942             else
6943             {
6944                 // We may still need the IL of the non-nonvisible methods for inlining in certain scenarios:
6945                 // dynamically emitted IL, friend assemblies or JITing of generic instantiations
6946                 region = CORCOMPILE_ILREGION_WARM;
6947             }
6948         }
6949     }
6950     EX_CATCH
6951     {
6952     }
6953     EX_END_CATCH(SwallowAllExceptions)
6954
6955     return region;
6956 }
6957
6958 CORINFO_CLASS_HANDLE CEEPreloader::FindTypeForProfileEntry(CORBBTPROF_BLOB_PARAM_SIG_ENTRY * profileBlobEntry)
6959 {
6960     STANDARD_VM_CONTRACT;
6961
6962     _ASSERTE(profileBlobEntry->blob.type == ParamTypeSpec);
6963
6964     if (PartialNGenStressPercentage() != 0)
6965         return CORINFO_CLASS_HANDLE( NULL );
6966
6967     Module *   pModule = GetAppDomain()->ToCompilationDomain()->GetTargetModule();
6968     TypeHandle th      = pModule->LoadIBCTypeHelper(profileBlobEntry);
6969
6970     return CORINFO_CLASS_HANDLE(th.AsPtr());
6971 }
6972
6973 CORINFO_METHOD_HANDLE CEEPreloader::FindMethodForProfileEntry(CORBBTPROF_BLOB_PARAM_SIG_ENTRY * profileBlobEntry)
6974 {
6975     STANDARD_VM_CONTRACT;
6976
6977     _ASSERTE(profileBlobEntry->blob.type == ParamMethodSpec);
6978
6979     if (PartialNGenStressPercentage() != 0)
6980         return CORINFO_METHOD_HANDLE( NULL );
6981     
6982     Module *      pModule = GetAppDomain()->ToCompilationDomain()->GetTargetModule();
6983     MethodDesc *  pMethod = pModule->LoadIBCMethodHelper(profileBlobEntry);
6984
6985     return CORINFO_METHOD_HANDLE( pMethod );
6986 }
6987
6988 void CEEPreloader::ReportInlining(CORINFO_METHOD_HANDLE inliner, CORINFO_METHOD_HANDLE inlinee)
6989 {
6990     STANDARD_VM_CONTRACT;
6991     m_image->ReportInlining(inliner, inlinee);
6992 }
6993
6994 void CEEPreloader::Link()
6995 {
6996     STANDARD_VM_CONTRACT;
6997
6998     COOPERATIVE_TRANSITION_BEGIN();
6999
7000     m_image->PreSave();
7001
7002     m_image->GetModule()->Save(m_image);
7003     m_image->GetModule()->Arrange(m_image);
7004     m_image->GetModule()->Fixup(m_image);
7005
7006     m_image->PostSave();
7007
7008     COOPERATIVE_TRANSITION_END();
7009 }
7010
7011 void CEEPreloader::FixupRVAs()
7012 {
7013     STANDARD_VM_CONTRACT;
7014
7015     COOPERATIVE_TRANSITION_BEGIN();
7016
7017     m_image->FixupRVAs();
7018
7019     COOPERATIVE_TRANSITION_END();
7020 }
7021
7022 void CEEPreloader::SetRVAsForFields(IMetaDataEmit * pEmit)
7023 {
7024     STANDARD_VM_CONTRACT;
7025
7026     COOPERATIVE_TRANSITION_BEGIN();
7027
7028     m_image->SetRVAsForFields(pEmit);
7029
7030     COOPERATIVE_TRANSITION_END();
7031 }
7032
7033 void CEEPreloader::GetRVAFieldData(mdFieldDef fd, PVOID * ppData, DWORD * pcbSize, DWORD * pcbAlignment)
7034 {
7035     STANDARD_VM_CONTRACT;
7036
7037     COOPERATIVE_TRANSITION_BEGIN();
7038
7039     FieldDesc * pFD = m_image->GetModule()->LookupFieldDef(fd);
7040     if (pFD == NULL)
7041         ThrowHR(COR_E_TYPELOAD);
7042
7043     _ASSERTE(pFD->IsILOnlyRVAField());
7044
7045     UINT size = pFD->LoadSize();
7046
7047     // 
7048     // Compute an alignment for the data based on the alignment
7049     // of the RVA.  We'll align up to 8 bytes.
7050     //
7051
7052     UINT align = 1;
7053     DWORD rva = pFD->GetOffset();
7054     DWORD rvaTemp = rva;   
7055
7056     while ((rvaTemp&1) == 0 && align < 8 && align < size)
7057     {
7058         align <<= 1;
7059         rvaTemp >>= 1;
7060     }
7061
7062
7063     *ppData = pFD->GetStaticAddressHandle(NULL);
7064     *pcbSize = size;
7065     *pcbAlignment = align;
7066
7067     COOPERATIVE_TRANSITION_END();
7068 }
7069
7070 ULONG CEEPreloader::Release()
7071 {
7072     CONTRACTL {
7073         NOTHROW;
7074         GC_NOTRIGGER;
7075         MODE_ANY;
7076     } CONTRACTL_END;
7077
7078     delete this;
7079     return 0;
7080 }
7081
7082 void CEEPreloader::Error(mdToken token, Exception * pException)
7083 {
7084     STANDARD_VM_CONTRACT;
7085
7086     StackSString msg;
7087
7088 #ifdef CROSSGEN_COMPILE
7089     pException->GetMessage(msg);
7090 #else
7091     {
7092         GCX_COOP();
7093
7094         // Going though throwable gives more verbose error messages in certain cases that our tests depend on.
7095         OBJECTREF throwable = NingenEnabled() ? NULL : CLRException::GetThrowableFromException(pException);
7096
7097         if (throwable != NULL)
7098         {
7099             GetExceptionMessage(throwable, msg);
7100         }
7101         else
7102         {
7103             pException->GetMessage(msg);
7104         }
7105     }
7106 #endif
7107     
7108     m_pData->Error(token, pException->GetHR(), msg.GetUnicode());
7109 }
7110
7111 CEEInfo *g_pCEEInfo = NULL;
7112
7113 ICorDynamicInfo * __stdcall GetZapJitInfo()
7114 {
7115     STANDARD_VM_CONTRACT;
7116
7117     if (g_pCEEInfo == NULL)
7118     {
7119         CEEInfo * p = new CEEInfo();
7120         if (InterlockedCompareExchangeT(&g_pCEEInfo, p, NULL) != NULL)
7121             delete p;
7122     }
7123
7124     return g_pCEEInfo;
7125 }
7126
7127 CEECompileInfo *g_pCEECompileInfo = NULL;
7128
7129 ICorCompileInfo * __stdcall GetCompileInfo()
7130 {
7131     STANDARD_VM_CONTRACT;
7132
7133     if (g_pCEECompileInfo == NULL)
7134     {
7135         CEECompileInfo * p = new CEECompileInfo();
7136         if (InterlockedCompareExchangeT(&g_pCEECompileInfo, p, NULL) != NULL)
7137             delete p;
7138     }
7139
7140     return g_pCEECompileInfo;
7141 }
7142
7143 //
7144 // CompilationDomain
7145 //
7146
7147 CompilationDomain::CompilationDomain(BOOL fForceDebug,
7148                                      BOOL fForceProfiling,
7149                                      BOOL fForceInstrument)
7150   : m_fForceDebug(fForceDebug),
7151     m_fForceProfiling(fForceProfiling),
7152     m_fForceInstrument(fForceInstrument),
7153     m_pTargetAssembly(NULL),
7154     m_pTargetModule(NULL),
7155     m_pTargetImage(NULL),
7156     m_pEmit(NULL),
7157     m_pDependencyRefSpecs(NULL),
7158     m_pDependencies(NULL),
7159     m_cDependenciesCount(0),
7160     m_cDependenciesAlloc(0)
7161 {
7162     STANDARD_VM_CONTRACT;
7163
7164 }
7165
7166 void CompilationDomain::ReleaseDependencyEmitter()
7167 {
7168     m_pDependencyRefSpecs.Release();
7169
7170     m_pEmit.Release();
7171 }
7172
7173 CompilationDomain::~CompilationDomain()
7174 {
7175     CONTRACTL
7176     {
7177         NOTHROW;
7178         GC_TRIGGERS;
7179         MODE_ANY;
7180     }
7181     CONTRACTL_END;
7182
7183     if (m_pDependencies != NULL)
7184         delete [] m_pDependencies;
7185
7186     ReleaseDependencyEmitter();
7187
7188     for (unsigned i = 0; i < m_rRefCaches.Size(); i++)
7189     {
7190         delete m_rRefCaches[i];
7191         m_rRefCaches[i]=NULL;
7192     }
7193
7194 }
7195
7196 void CompilationDomain::Init()
7197 {
7198     STANDARD_VM_CONTRACT;
7199
7200 #ifndef CROSSGEN_COMPILE
7201     AppDomain::Init();
7202 #endif
7203
7204 #ifndef CROSSGEN_COMPILE
7205     // allocate a Virtual Call Stub Manager for the compilation domain
7206     InitVSD();
7207 #endif
7208
7209     Security::SetDefaultAppDomainProperty(GetSecurityDescriptor());
7210     SetCompilationDomain();
7211
7212
7213 #ifdef _DEBUG 
7214     g_pConfig->DisableGenerateStubForHost();
7215 #endif
7216 }
7217
7218 HRESULT CompilationDomain::AddDependencyEntry(PEAssembly *pFile,
7219                                            mdAssemblyRef ref,
7220                                            mdAssemblyRef def)
7221 {
7222 #ifdef _DEBUG
7223     // This method is not multi-thread safe.  This is OK because it is only called by NGen compiling, which is
7224     // effectively single-threaded.  The following code verifies that we're not called on multiple threads.
7225     static volatile LONG threadId = 0;
7226     if (threadId == 0)
7227     {
7228         InterlockedCompareExchange(&threadId, GetCurrentThreadId(), 0);
7229     }
7230     _ASSERTE((LONG)GetCurrentThreadId() == threadId);
7231 #endif // _DEBUG
7232
7233     _ASSERTE((pFile == NULL) == (def == mdAssemblyRefNil));
7234
7235     if (m_cDependenciesCount == m_cDependenciesAlloc)
7236     {
7237         // Save the new count in a local variable.  Can't update m_cDependenciesAlloc until the new
7238         // CORCOMPILE_DEPENDENCY array is allocated, otherwise an out-of-memory exception from new[]
7239         // operator would put the data in an inconsistent state, causing heap corruption later.
7240         USHORT cNewDependenciesAlloc = m_cDependenciesAlloc == 0 ? 20 : m_cDependenciesAlloc * 2;
7241
7242         // Grow m_pDependencies
7243
7244         NewArrayHolder<CORCOMPILE_DEPENDENCY> pNewDependencies(new CORCOMPILE_DEPENDENCY[cNewDependenciesAlloc]);
7245         {
7246             // This block must execute transactionally. No throwing allowed. No bailing allowed.
7247             FAULT_FORBID();
7248
7249             memset(pNewDependencies,  0, cNewDependenciesAlloc*sizeof(CORCOMPILE_DEPENDENCY));
7250
7251             if (m_pDependencies)
7252             {
7253                 memcpy(pNewDependencies, m_pDependencies,
7254                        m_cDependenciesCount*sizeof(CORCOMPILE_DEPENDENCY));
7255     
7256                 delete [] m_pDependencies;
7257             }
7258     
7259             m_pDependencies = pNewDependencies.Extract();
7260             m_cDependenciesAlloc = cNewDependenciesAlloc;
7261         }
7262     }
7263
7264     CORCOMPILE_DEPENDENCY *pDependency = &m_pDependencies[m_cDependenciesCount++];
7265
7266     // Clear memory so that we won't write random data into the zapped file
7267     ZeroMemory(pDependency, sizeof(CORCOMPILE_DEPENDENCY));
7268
7269     pDependency->dwAssemblyRef = ref;
7270
7271     pDependency->dwAssemblyDef = def;
7272
7273     pDependency->signNativeImage = INVALID_NGEN_SIGNATURE;
7274
7275     if (pFile)
7276     {
7277         DomainAssembly *pAssembly = GetAppDomain()->LoadDomainAssembly(NULL, pFile, FILE_LOAD_CREATE, NULL);
7278         // Note that this can trigger an assembly load (of mscorlib)
7279         pAssembly->GetOptimizedIdentitySignature(&pDependency->signAssemblyDef);
7280
7281
7282
7283         //
7284         // This is done in CompilationDomain::CanEagerBindToZapFile with full support for hardbinding
7285         //
7286         if (pFile->IsSystem() && pFile->HasNativeImage())
7287         {
7288             CORCOMPILE_VERSION_INFO * pNativeVersion = pFile->GetLoadedNative()->GetNativeVersionInfo();
7289             pDependency->signNativeImage = pNativeVersion->signature;
7290         }
7291
7292     }
7293
7294     return S_OK;
7295 }
7296
7297 HRESULT CompilationDomain::AddDependency(AssemblySpec *pRefSpec,
7298                                          PEAssembly * pFile)
7299 {
7300     HRESULT hr;
7301
7302     //
7303     // Record the dependency
7304     //
7305
7306     // This assert prevents dependencies from silently being loaded without being recorded.
7307     _ASSERTE(m_pEmit);
7308
7309     // Normalize any reference to mscorlib; we don't want to record other non-canonical
7310     // mscorlib references in the ngen image since fusion doesn't understand how to bind them.
7311     // (Not to mention the fact that they are redundant.)
7312     AssemblySpec spec;
7313     if (pRefSpec->IsMscorlib())
7314     {
7315         _ASSERTE(pFile); // mscorlib had better not be missing
7316         if (!pFile)
7317             return E_UNEXPECTED;
7318
7319         // Don't store a binding from mscorlib to itself.
7320         if (m_pTargetAssembly == SystemDomain::SystemAssembly())
7321             return S_OK;
7322
7323         spec.InitializeSpec(pFile);
7324         pRefSpec = &spec;
7325     }
7326     else if (m_pTargetAssembly == NULL && pFile)
7327     {
7328         // If target assembly is still NULL, we must be loading either the target assembly or mscorlib.
7329         // Mscorlib is already handled above, so we must be loading the target assembly if we get here.
7330         // Use the assembly name given in the target assembly so that the native image is deterministic
7331         // regardless of how the target assembly is specified on the command line.
7332         spec.InitializeSpec(pFile);
7333         if (spec.IsStrongNamed() && spec.HasPublicKey())
7334         {
7335             spec.ConvertPublicKeyToToken();
7336         }
7337         pRefSpec = &spec;
7338     }
7339     else if (pRefSpec->IsStrongNamed() && pRefSpec->HasPublicKey())
7340     {
7341         // Normalize to always use public key token.  Otherwise we may insert one reference
7342         // using public key, and another reference using public key token.
7343         spec.CopyFrom(pRefSpec);
7344         spec.ConvertPublicKeyToToken();
7345         pRefSpec = &spec;
7346     }
7347
7348 #ifdef FEATURE_COMINTEROP
7349     // Only cache ref specs that have a unique identity. This is needed to avoid caching
7350     // things like WinRT type specs, which would benefit very little from being cached.
7351     if (!pRefSpec->HasUniqueIdentity())
7352     {
7353         // Successful bind of a reference with a non-unique assembly identity.
7354         _ASSERTE(pRefSpec->IsContentType_WindowsRuntime());
7355
7356         AssemblySpec defSpec;
7357         if (pFile != NULL)
7358         {
7359             defSpec.InitializeSpec(pFile);
7360
7361             // Windows Runtime Native Image binding depends on details exclusively described by the definition winmd file.
7362             // Therefore we can actually drop the existing ref spec here entirely.
7363             // Also, Windows Runtime Native Image binding uses the simple name of the ref spec as the
7364             // resolution rule for PreBind when finding definition assemblies.
7365             // See comment on CLRPrivBinderWinRT::PreBind for further details.
7366             pRefSpec = &defSpec;
7367         }
7368
7369         // Unfortunately, we don't have any choice regarding failures (pFile == NULL) because
7370         // there is no value to canonicalize on (i.e., a def spec created from a non-NULL
7371         // pFile) and so we must cache all non-unique-assembly-id failures.
7372         const AssemblySpecDefRefMapEntry * pEntry = m_dependencyDefRefMap.LookupPtr(&defSpec);
7373         if (pFile == NULL || pEntry == NULL)
7374         {
7375             mdAssemblyRef refToken = mdAssemblyRefNil;
7376             IfFailRet(pRefSpec->EmitToken(m_pEmit, &refToken, TRUE, TRUE));
7377
7378             mdAssemblyRef defToken = mdAssemblyRefNil;
7379             if (pFile != NULL)
7380             {
7381                 IfFailRet(defSpec.EmitToken(m_pEmit, &defToken, TRUE, TRUE));
7382
7383                 NewHolder<AssemblySpec> pNewDefSpec = new AssemblySpec();
7384                 pNewDefSpec->CopyFrom(&defSpec);
7385                 pNewDefSpec->CloneFields();
7386
7387                 NewHolder<AssemblySpec> pNewRefSpec = new AssemblySpec();
7388                 pNewRefSpec->CopyFrom(pRefSpec);
7389                 pNewRefSpec->CloneFields();
7390
7391                 _ASSERTE(m_dependencyDefRefMap.LookupPtr(pNewDefSpec) == NULL);
7392
7393                 AssemblySpecDefRefMapEntry e;
7394                 e.m_pDef = pNewDefSpec;
7395                 e.m_pRef = pNewRefSpec;
7396                 m_dependencyDefRefMap.Add(e);
7397
7398                 pNewDefSpec.SuppressRelease();
7399                 pNewRefSpec.SuppressRelease();
7400             }
7401
7402             IfFailRet(AddDependencyEntry(pFile, refToken, defToken));
7403         }
7404     }
7405     else
7406 #endif // FEATURE_COMINTEROP
7407     {
7408         //
7409         // See if we've already added the contents of the ref
7410         // Else, emit token for the ref
7411         //
7412
7413         if (m_pDependencyRefSpecs->Store(pRefSpec))
7414             return S_OK;
7415
7416         mdAssemblyRef refToken;
7417         IfFailRet(pRefSpec->EmitToken(m_pEmit, &refToken));
7418
7419         //
7420         // Make a spec for the bound assembly
7421         //
7422
7423         mdAssemblyRef defToken = mdAssemblyRefNil;
7424
7425         // All dependencies of a shared assembly need to be shared. So for a shared
7426         // assembly, we want to remember the missing assembly ref during ngen, so that
7427         // we can probe eagerly for the dependency at load time, and make sure that
7428         // it is loaded as shared.
7429         // In such a case, pFile will be NULL
7430         if (pFile)
7431         {
7432             AssemblySpec assemblySpec;
7433             assemblySpec.InitializeSpec(pFile);
7434
7435             IfFailRet(assemblySpec.EmitToken(m_pEmit, &defToken));
7436         }
7437
7438         //
7439         // Add the entry.  Include the PEFile if we are not doing explicit bindings.
7440         //
7441
7442         IfFailRet(AddDependencyEntry(pFile, refToken, defToken));
7443     }
7444
7445     return S_OK;
7446 }
7447
7448 //----------------------------------------------------------------------------
7449 AssemblySpec* CompilationDomain::FindAssemblyRefSpecForDefSpec(
7450     AssemblySpec* pDefSpec)
7451 {
7452     WRAPPER_NO_CONTRACT;
7453
7454     if (pDefSpec == nullptr)
7455         return nullptr;
7456
7457     const AssemblySpecDefRefMapEntry * pEntry = m_dependencyDefRefMap.LookupPtr(pDefSpec);
7458     _ASSERTE(pEntry != NULL);
7459
7460     return (pEntry != NULL) ? pEntry->m_pRef : NULL;
7461 }
7462
7463
7464 //----------------------------------------------------------------------------
7465 // Is it OK to embed direct pointers to an ngen dependency?
7466 // true if hardbinding is OK, false otherwise
7467 //
7468 // targetModule - The pointer points into the native image of this Module.
7469 //                If this native image gets relocated, the native image of
7470 //                the source Module is invalidated unless the embedded
7471 //                pointer can be fixed up appropriately.
7472 // limitToHardBindList - Is it OK to hard-bind to a dependency even if it is
7473 //                not asked for explicitly?
7474
7475 BOOL CompilationDomain::CanEagerBindToZapFile(Module *targetModule, BOOL limitToHardBindList)
7476 {
7477     // We do this check before checking the hashtables because m_cantHardBindModules
7478     // will contain non-manifest modules. However, we do want them to be able
7479     // to hard-bind to themselves
7480     if (targetModule == m_pTargetModule)
7481     {
7482         return TRUE;
7483     }
7484
7485     //
7486     // CoreCLR does not have attributes for fine grained eager binding control.
7487     // We hard bind to mscorlib.dll only.
7488     //
7489     return targetModule->IsSystem();
7490 }
7491
7492
7493 void CompilationDomain::SetTarget(Assembly *pAssembly, Module *pModule)
7494 {
7495     STANDARD_VM_CONTRACT;
7496
7497     m_pTargetAssembly = pAssembly;
7498     m_pTargetModule = pModule;
7499 }
7500
7501 void CompilationDomain::SetTargetImage(DataImage *pImage, CEEPreloader * pPreloader)
7502 {
7503     STANDARD_VM_CONTRACT;
7504
7505     m_pTargetImage = pImage;
7506     m_pTargetPreloader = pPreloader;
7507
7508     _ASSERTE(pImage->GetModule() == GetTargetModule());
7509 }
7510
7511 void ReportMissingDependency(Exception * e)
7512 {
7513     // Avoid duplicate error messages
7514     if (FAILED(g_hrFatalError))
7515         return;
7516
7517     SString s;
7518
7519     e->GetMessage(s);
7520     GetSvcLogger()->Printf(LogLevel_Error, W("Error: %s\n"), s.GetUnicode());
7521
7522     g_hrFatalError = COR_E_FILELOAD;
7523 }
7524
7525 PEAssembly *CompilationDomain::BindAssemblySpec(
7526     AssemblySpec *pSpec,
7527     BOOL fThrowOnFileNotFound,
7528     BOOL fRaisePrebindEvents,
7529     StackCrawlMark *pCallerStackMark,
7530     AssemblyLoadSecurity *pLoadSecurity,
7531     BOOL fUseHostBinderIfAvailable)
7532 {
7533     PEAssembly *pFile = NULL;
7534     //
7535     // Do the binding
7536     //
7537
7538     EX_TRY
7539     {
7540         //
7541         // Use normal binding rules
7542         // (possibly with our custom IApplicationContext)
7543         //
7544         pFile = AppDomain::BindAssemblySpec(
7545             pSpec,
7546             fThrowOnFileNotFound,
7547             fRaisePrebindEvents,
7548             pCallerStackMark,
7549             pLoadSecurity,
7550             fUseHostBinderIfAvailable);
7551     }
7552     EX_HOOK
7553     {
7554         if (!g_fNGenMissingDependenciesOk)
7555         {
7556             ReportMissingDependency(GET_EXCEPTION());
7557             EX_RETHROW;
7558         }
7559
7560         //
7561         // Record missing dependencies
7562         //
7563 #ifdef FEATURE_COMINTEROP                
7564         if (!g_fNGenWinMDResilient || pSpec->HasUniqueIdentity())
7565 #endif
7566         {
7567             IfFailThrow(AddDependency(pSpec, NULL));
7568         }
7569     }
7570     EX_END_HOOK
7571
7572 #ifdef FEATURE_COMINTEROP                
7573     if (!g_fNGenWinMDResilient || pSpec->HasUniqueIdentity())
7574 #endif
7575     {
7576         IfFailThrow(AddDependency(pSpec, pFile));
7577     }
7578
7579     return pFile;
7580 }
7581
7582 HRESULT
7583     CompilationDomain::SetContextInfo(LPCWSTR path, BOOL isExe)
7584 {
7585     STANDARD_VM_CONTRACT;
7586
7587     HRESULT hr = S_OK;
7588
7589     COOPERATIVE_TRANSITION_BEGIN();
7590
7591 #ifdef FEATURE_FUSION
7592     if (isExe)
7593     {
7594         if (NingenEnabled())
7595         {
7596             WCHAR buf[MAX_LONGPATH + sizeof(CONFIGURATION_EXTENSION)/sizeof(WCHAR) + 1];
7597             if (0 != wcscpy_s(buf, sizeof(buf)/sizeof(*buf), path))
7598             {
7599                 COMPlusThrowHR(COR_E_PATHTOOLONG);
7600             }
7601             WCHAR *pSlash = wcsrchr(buf, W('\\'));
7602             if (!pSlash)
7603             {
7604                 COMPlusThrowHR(COR_E_BAD_PATHNAME);
7605             }
7606
7607             *(pSlash + 1) = W('\0');
7608             hr = m_pFusionContext->Set(ACTAG_APP_BASE_URL, buf, (DWORD)((wcslen(buf) + 1) * sizeof(WCHAR)), 0);
7609             if (FAILED(hr))
7610             {
7611                 COMPlusThrowHR(hr);
7612             }
7613
7614             if (0 != wcscpy_s(buf, sizeof(buf)/sizeof(*buf), path + (pSlash - buf) + 1))
7615             {
7616                 COMPlusThrowHR(COR_E_PATHTOOLONG);
7617             }
7618
7619             if (0 != wcscat_s(buf, sizeof(buf)/sizeof(*buf), CONFIGURATION_EXTENSION))
7620             {
7621                 COMPlusThrowHR(COR_E_PATHTOOLONG);
7622             }
7623             hr = m_pFusionContext->Set(ACTAG_APP_CONFIG_FILE, buf, (DWORD)((wcslen(buf) + 1) * sizeof(WCHAR)), 0);
7624             if (FAILED(hr))
7625             {
7626                 COMPlusThrowHR(hr);
7627             }
7628         }
7629         else
7630         {
7631             SetupExecutableFusionContext(path);
7632         }
7633     }
7634     else
7635     {
7636         hr = m_pFusionContext->Set(ACTAG_APP_BASE_URL,
7637                                    (void*) path, (DWORD) ((wcslen(path)+1) * sizeof(WCHAR)),
7638                                    0);
7639     }
7640 #endif //FEATURE_FUSION
7641
7642     COOPERATIVE_TRANSITION_END();
7643
7644     return hr;
7645 }
7646
7647 void CompilationDomain::SetDependencyEmitter(IMetaDataAssemblyEmit *pEmit)
7648 {
7649     STANDARD_VM_CONTRACT;
7650
7651     pEmit->AddRef();
7652     m_pEmit = pEmit;
7653
7654     m_pDependencyRefSpecs = new AssemblySpecHash();
7655 }
7656
7657
7658 HRESULT
7659     CompilationDomain::GetDependencies(CORCOMPILE_DEPENDENCY **ppDependencies,
7660                                        DWORD *pcDependencies)
7661 {
7662     STANDARD_VM_CONTRACT;
7663
7664
7665     //
7666     // Return the bindings.
7667     //
7668
7669     *ppDependencies = m_pDependencies;
7670     *pcDependencies = m_cDependenciesCount;
7671
7672     // Cannot add any more dependencies
7673     ReleaseDependencyEmitter();
7674
7675     return S_OK;
7676 }
7677
7678 #ifdef FEATURE_FUSION
7679 HRESULT
7680     CompilationDomain::GetIBindContext(IBindContext **ppBindCtx)
7681 {
7682     LIMITED_METHOD_CONTRACT;
7683     HRESULT hr = S_OK;
7684
7685     ReleaseHolder<IBindContext> pBindCtx;
7686     if (HasLoadContextHostBinder())
7687     {
7688         IfFailRet(GetCurrentLoadContextHostBinder()->QueryInterface(__uuidof(IBindContext), &pBindCtx));
7689     }
7690     else
7691     {
7692         GetBindContextFromApplicationContext(BaseDomain::GetFusionContext(), &pBindCtx); // Can't fail
7693     }
7694
7695     *ppBindCtx = pBindCtx.Extract();
7696     return S_OK;
7697 }
7698 #endif
7699
7700 #ifdef CROSSGEN_COMPILE
7701 HRESULT CompilationDomain::SetPlatformWinmdPaths(LPCWSTR pwzPlatformWinmdPaths)
7702 {
7703     STANDARD_VM_CONTRACT;
7704
7705 #ifdef FEATURE_COMINTEROP
7706     // 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
7707     StringArrayList *saPaths = new StringArrayList();
7708
7709     SString strPaths(pwzPlatformWinmdPaths);
7710     if (!strPaths.IsEmpty())
7711     {
7712         for (SString::Iterator i = strPaths.Begin(); i != strPaths.End(); )
7713         {
7714             // Skip any leading spaces or semicolons
7715             if (strPaths.Skip(i, W(';')))
7716             {
7717                 continue;
7718             }
7719         
7720             SString::Iterator iEnd = i;     // Where current assembly name ends
7721             SString::Iterator iNext;        // Where next assembly name starts
7722             if (strPaths.Find(iEnd, W(';')))
7723             {
7724                 iNext = iEnd + 1;
7725             }
7726             else
7727             {
7728                 iNext = iEnd = strPaths.End();
7729             }
7730         
7731             _ASSERTE(i < iEnd);
7732             if(i != iEnd)
7733             {
7734                 saPaths->Append(SString(strPaths, i, iEnd));
7735             }
7736             i = iNext;
7737         }
7738     }
7739     Crossgen::SetFirstPartyWinMDPaths(saPaths);
7740 #endif // FEATURE_COMINTEROP
7741
7742     return S_OK;
7743 }
7744 #endif // CROSSGEN_COMPILE
7745
7746
7747 #endif // FEATURE_PREJIT