[Tizen] Disable jithost arena cache
[platform/upstream/coreclr.git] / src / zap / zapimage.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 // ZapImage.cpp
6 //
7
8 //
9 // NGEN-specific infrastructure for writing PE files.
10 // 
11 // ======================================================================================
12
13 #include "common.h"
14 #include "strsafe.h"
15
16 #include "zaprelocs.h"
17
18 #include "zapinnerptr.h"
19 #include "zapwrapper.h"
20
21 #include "zapheaders.h"
22 #include "zapmetadata.h"
23 #include "zapcode.h"
24 #include "zapimport.h"
25
26 #ifdef FEATURE_READYTORUN_COMPILER
27 #include "zapreadytorun.h"
28 #endif
29
30 #include "md5.h"
31
32 // This is RTL_CONTAINS_FIELD from ntdef.h
33 #define CONTAINS_FIELD(Struct, Size, Field) \
34     ( (((PCHAR)(&(Struct)->Field)) + sizeof((Struct)->Field)) <= (((PCHAR)(Struct))+(Size)) )
35
36 /* --------------------------------------------------------------------------- *
37  * Destructor wrapper objects
38  * --------------------------------------------------------------------------- */
39
40 ZapImage::ZapImage(Zapper *zapper)
41   : m_zapper(zapper),
42     m_stats(new ZapperStats())
43     /* Everything else is initialized to 0 by default */
44 {
45 }
46
47 ZapImage::~ZapImage()
48 {
49 #ifdef ZAP_HASHTABLE_TUNING
50     // If ZAP_HASHTABLE_TUNING is defined, preallocate is overloaded to print the tunning constants
51     Preallocate();
52 #endif
53
54     //
55     // Clean up.
56     //
57     if (m_stats != NULL)
58             delete m_stats;
59
60     if (m_pModuleFileName != NULL)
61         delete [] m_pModuleFileName;
62
63     if (m_pMDImport != NULL)
64         m_pMDImport->Release();
65
66     if (m_pAssemblyEmit != NULL)
67         m_pAssemblyEmit->Release();
68
69     if (m_profileDataFile != NULL)
70         UnmapViewOfFile(m_profileDataFile);
71
72     if (m_pPreloader)
73         m_pPreloader->Release();
74
75     if (m_pImportSectionsTable != NULL)
76         m_pImportSectionsTable->~ZapImportSectionsTable();
77
78     if (m_pGCInfoTable != NULL)
79         m_pGCInfoTable->~ZapGCInfoTable();
80
81 #ifdef WIN64EXCEPTIONS
82     if (m_pUnwindDataTable != NULL)
83         m_pUnwindDataTable->~ZapUnwindDataTable();
84 #endif
85
86     if (m_pStubDispatchDataTable != NULL)
87         m_pStubDispatchDataTable->~ZapImportSectionSignatures();
88
89     if (m_pExternalMethodDataTable != NULL)
90         m_pExternalMethodDataTable->~ZapImportSectionSignatures();
91
92     if (m_pDynamicHelperDataTable != NULL)
93         m_pDynamicHelperDataTable->~ZapImportSectionSignatures();
94
95     if (m_pDebugInfoTable != NULL)
96         m_pDebugInfoTable->~ZapDebugInfoTable();
97
98     if (m_pVirtualSectionsTable != NULL)
99         m_pVirtualSectionsTable->~ZapVirtualSectionsTable();
100
101     if (m_pILMetaData != NULL)
102         m_pILMetaData->~ZapILMetaData();
103
104     if (m_pBaseRelocs != NULL)
105         m_pBaseRelocs->~ZapBaseRelocs();
106
107     if (m_pAssemblyMetaData != NULL)
108         m_pAssemblyMetaData->~ZapMetaData();
109
110     //
111     // Destruction of auxiliary tables in alphabetical order
112     //
113
114     if (m_pImportTable != NULL) 
115         m_pImportTable->~ZapImportTable();
116
117     if (m_pInnerPtrs != NULL) 
118         m_pInnerPtrs->~ZapInnerPtrTable();
119
120     if (m_pMethodEntryPoints != NULL)
121         m_pMethodEntryPoints->~ZapMethodEntryPointTable();
122
123     if (m_pWrappers != NULL) 
124         m_pWrappers->~ZapWrapperTable();
125 }
126
127 void ZapImage::InitializeSections()
128 {
129     AllocateVirtualSections();
130
131     m_pCorHeader = new (GetHeap()) ZapCorHeader(this);
132     m_pHeaderSection->Place(m_pCorHeader);
133
134     SetDirectoryEntry(IMAGE_DIRECTORY_ENTRY_COMHEADER, m_pCorHeader);
135
136     m_pNativeHeader = new (GetHeap()) ZapNativeHeader(this);
137     m_pHeaderSection->Place(m_pNativeHeader);
138
139     m_pCodeManagerEntry = new (GetHeap()) ZapCodeManagerEntry(this);
140     m_pHeaderSection->Place(m_pCodeManagerEntry);
141
142     m_pImportSectionsTable = new (GetHeap()) ZapImportSectionsTable(this);
143     m_pImportTableSection->Place(m_pImportSectionsTable);
144
145     m_pExternalMethodDataTable = new (GetHeap()) ZapImportSectionSignatures(this, m_pExternalMethodThunkSection, m_pGCSection);
146     m_pExternalMethodDataSection->Place(m_pExternalMethodDataTable);
147
148     m_pStubDispatchDataTable = new (GetHeap()) ZapImportSectionSignatures(this, m_pStubDispatchCellSection, m_pGCSection);
149     m_pStubDispatchDataSection->Place(m_pStubDispatchDataTable);
150
151     m_pImportTable = new (GetHeap()) ZapImportTable(this);
152
153     m_pGCInfoTable = new (GetHeap()) ZapGCInfoTable(this);
154     m_pExceptionInfoLookupTable = new (GetHeap()) ZapExceptionInfoLookupTable(this);
155
156 #ifdef WIN64EXCEPTIONS
157     m_pUnwindDataTable = new (GetHeap()) ZapUnwindDataTable(this);
158 #endif
159
160     m_pEEInfoTable = ZapBlob::NewAlignedBlob(this, NULL, sizeof(CORCOMPILE_EE_INFO_TABLE), TARGET_POINTER_SIZE);
161     m_pEETableSection->Place(m_pEEInfoTable);
162
163     //
164     // Allocate Helper table, and fill it out
165     //
166
167     m_pHelperThunks = new (GetHeap()) ZapNode * [CORINFO_HELP_COUNT];
168
169     if (!m_zapper->m_pOpt->m_fNoMetaData)
170     {
171         m_pILMetaData = new (GetHeap()) ZapILMetaData(this);
172         m_pILMetaDataSection->Place(m_pILMetaData);
173     }
174
175     m_pDebugInfoTable = new (GetHeap()) ZapDebugInfoTable(this);
176     m_pDebugSection->Place(m_pDebugInfoTable);
177
178     m_pBaseRelocs = new (GetHeap()) ZapBaseRelocs(this);
179     m_pBaseRelocsSection->Place(m_pBaseRelocs);
180
181     SetDirectoryEntry(IMAGE_DIRECTORY_ENTRY_BASERELOC, m_pBaseRelocsSection);
182
183     //
184     // Initialization of auxiliary tables in alphabetical order
185     //
186     m_pInnerPtrs = new (GetHeap()) ZapInnerPtrTable(this);
187     m_pMethodEntryPoints = new (GetHeap()) ZapMethodEntryPointTable(this);
188     m_pWrappers = new (GetHeap()) ZapWrapperTable(this);
189
190     // Place the virtual sections tables in debug section. It exists for diagnostic purposes
191     // only and should not be touched under normal circumstances    
192     m_pVirtualSectionsTable = new (GetHeap()) ZapVirtualSectionsTable(this);
193     m_pDebugSection->Place(m_pVirtualSectionsTable);
194
195 #ifndef ZAP_HASHTABLE_TUNING
196     Preallocate();
197 #endif
198 }
199
200 #ifdef FEATURE_READYTORUN_COMPILER
201 void ZapImage::InitializeSectionsForReadyToRun()
202 {
203     AllocateVirtualSections();
204
205     // Preload sections are not used for ready to run. Clear the pointers to them to catch accidental use.
206     for (int i = 0; i < CORCOMPILE_SECTION_COUNT; i++)
207         m_pPreloadSections[i] = NULL;
208
209     m_pCorHeader = new (GetHeap()) ZapCorHeader(this);
210     m_pHeaderSection->Place(m_pCorHeader);
211
212     SetDirectoryEntry(IMAGE_DIRECTORY_ENTRY_COMHEADER, m_pCorHeader);
213
214     m_pNativeHeader = new (GetHeap()) ZapReadyToRunHeader(this);
215     m_pHeaderSection->Place(m_pNativeHeader);
216
217     m_pImportSectionsTable = new (GetHeap()) ZapImportSectionsTable(this);
218     m_pHeaderSection->Place(m_pImportSectionsTable);
219
220     {
221 #define COMPILER_NAME "CoreCLR"
222
223         const char * pCompilerIdentifier = COMPILER_NAME " " FX_FILEVERSION_STR " " QUOTE_MACRO(__BUILDMACHINE__);
224         ZapBlob * pCompilerIdentifierBlob = new (GetHeap()) ZapBlobPtr((PVOID)pCompilerIdentifier, strlen(pCompilerIdentifier) + 1);
225
226         GetReadyToRunHeader()->RegisterSection(READYTORUN_SECTION_COMPILER_IDENTIFIER, pCompilerIdentifierBlob);
227         m_pHeaderSection->Place(pCompilerIdentifierBlob);
228     }
229
230     m_pImportTable = new (GetHeap()) ZapImportTable(this);
231
232     for (int i=0; i<ZapImportSectionType_Total; i++)
233     {
234         ZapVirtualSection * pSection;
235         if (i == ZapImportSectionType_Eager)
236             pSection = m_pDelayLoadInfoDelayListSectionEager;
237         else
238         if (i < ZapImportSectionType_Cold)
239             pSection = m_pDelayLoadInfoDelayListSectionHot;
240         else
241             pSection = m_pDelayLoadInfoDelayListSectionCold;
242
243         m_pDelayLoadInfoDataTable[i] = new (GetHeap()) ZapImportSectionSignatures(this, m_pDelayLoadInfoTableSection[i]);
244         pSection->Place(m_pDelayLoadInfoDataTable[i]);
245     }
246
247     m_pDynamicHelperDataTable = new (GetHeap()) ZapImportSectionSignatures(this, m_pDynamicHelperCellSection);
248     m_pDynamicHelperDataSection->Place(m_pDynamicHelperDataTable);
249
250     m_pExternalMethodDataTable = new (GetHeap()) ZapImportSectionSignatures(this, m_pExternalMethodCellSection, m_pGCSection);
251     m_pExternalMethodDataSection->Place(m_pExternalMethodDataTable);
252
253     m_pStubDispatchDataTable = new (GetHeap()) ZapImportSectionSignatures(this, m_pStubDispatchCellSection, m_pGCSection);
254     m_pStubDispatchDataSection->Place(m_pStubDispatchDataTable);
255
256     m_pGCInfoTable = new (GetHeap()) ZapGCInfoTable(this);
257
258 #ifdef WIN64EXCEPTIONS
259     m_pUnwindDataTable = new (GetHeap()) ZapUnwindDataTable(this);
260 #endif
261
262     m_pILMetaData = new (GetHeap()) ZapILMetaData(this);
263     m_pILMetaDataSection->Place(m_pILMetaData);
264
265     m_pBaseRelocs = new (GetHeap()) ZapBaseRelocs(this);
266     m_pBaseRelocsSection->Place(m_pBaseRelocs);
267
268     SetDirectoryEntry(IMAGE_DIRECTORY_ENTRY_BASERELOC, m_pBaseRelocsSection);
269
270     //
271     // Initialization of auxiliary tables in alphabetical order
272     //
273     m_pInnerPtrs = new (GetHeap()) ZapInnerPtrTable(this);
274
275     m_pExceptionInfoLookupTable = new (GetHeap()) ZapExceptionInfoLookupTable(this);
276
277     //
278     // Always allocate slot for module - it is used to determine that the image is used
279     //
280     m_pImportTable->GetPlacedHelperImport(READYTORUN_HELPER_Module);
281
282     //
283     // Make sure the import sections table is in the image, so we can find the slot for module
284     //
285     _ASSERTE(m_pImportSectionsTable->GetSize() != 0);
286     GetReadyToRunHeader()->RegisterSection(READYTORUN_SECTION_IMPORT_SECTIONS, m_pImportSectionsTable);
287 }
288 #endif // FEATURE_READYTORUN_COMPILER
289
290
291 #define DATA_MEM_READONLY IMAGE_SCN_MEM_READ
292 #define DATA_MEM_WRITABLE IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE
293 #define XDATA_MEM         IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE
294 #define TEXT_MEM          IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ
295
296 void ZapImage::AllocateVirtualSections()
297 {
298     //
299     // Allocate all virtual sections in the order they will appear in the final image
300     //
301     // To maximize packing of the data in the native image, the number of named physical sections is minimized -  
302     // the named physical sections are used just for memory protection control. All items with the same memory
303     // protection are packed together in one physical section.
304     //
305
306     {
307         //
308         // .data section
309         //
310         DWORD access = DATA_MEM_WRITABLE;
311
312 #ifdef FEATURE_LAZY_COW_PAGES
313         // READYTORUN: FUTURE: Optional support for COW pages
314         if (!IsReadyToRunCompilation() && CLRConfig::GetConfigValue(CLRConfig::INTERNAL_ZapLazyCOWPagesEnabled))
315             access = DATA_MEM_READONLY;
316 #endif
317
318         ZapPhysicalSection * pDataSection = NewPhysicalSection(".data", IMAGE_SCN_CNT_INITIALIZED_DATA | access);
319
320         m_pPreloadSections[CORCOMPILE_SECTION_MODULE] = NewVirtualSection(pDataSection, IBCUnProfiledSection | HotRange | ModuleSection);
321
322         m_pEETableSection = NewVirtualSection(pDataSection, IBCUnProfiledSection | HotRange | EETableSection); // Could be marked bss if it makes sense
323
324         // These are all known to be hot or writeable
325         m_pPreloadSections[CORCOMPILE_SECTION_WRITE] = NewVirtualSection(pDataSection, IBCProfiledSection | HotRange | WriteDataSection);
326         m_pPreloadSections[CORCOMPILE_SECTION_HOT_WRITEABLE] = NewVirtualSection(pDataSection, IBCProfiledSection | HotRange | WriteableDataSection); // hot for reading, potentially written to 
327         m_pPreloadSections[CORCOMPILE_SECTION_WRITEABLE] = NewVirtualSection(pDataSection, IBCProfiledSection | ColdRange | WriteableDataSection); // Cold based on IBC profiling data.
328         m_pPreloadSections[CORCOMPILE_SECTION_HOT] = NewVirtualSection(pDataSection, IBCProfiledSection | HotRange | DataSection);
329
330         m_pPreloadSections[CORCOMPILE_SECTION_RVA_STATICS_HOT] = NewVirtualSection(pDataSection, IBCProfiledSection | HotRange | RVAStaticsSection);
331
332         m_pDelayLoadInfoTableSection[ZapImportSectionType_Eager] = NewVirtualSection(pDataSection, IBCUnProfiledSection | HotRange | DelayLoadInfoTableEagerSection, TARGET_POINTER_SIZE);
333
334         //
335         // Allocate dynamic info tables
336         //
337
338         // Place the HOT CorCompileTables now, the cold ones would be placed later in this routine (after other HOT sections)
339         for (int i=0; i<ZapImportSectionType_Count; i++)
340         {
341             m_pDelayLoadInfoTableSection[i] = NewVirtualSection(pDataSection, IBCProfiledSection | HotRange | DelayLoadInfoTableSection, TARGET_POINTER_SIZE);
342         }
343
344         m_pDynamicHelperCellSection = NewVirtualSection(pDataSection, IBCProfiledSection | HotColdSortedRange | ExternalMethodDataSection, TARGET_POINTER_SIZE);
345
346         m_pExternalMethodCellSection = NewVirtualSection(pDataSection, IBCProfiledSection | HotColdSortedRange | ExternalMethodThunkSection, TARGET_POINTER_SIZE);
347
348         // m_pStubDispatchCellSection is  deliberately placed  directly after
349         // the last m_pDelayLoadInfoTableSection (all .data sections go together in the order indicated).
350         // We do this to place it as the last "hot, written" section.  Why? Because
351         // we don't split the dispatch cells into hot/cold sections (We probably should),
352         // and so the section is actually half hot and half cold.
353         // But it turns out that the hot dispatch cells always come
354         // first (because the code that uses them is hot and gets compiled first).
355         // Thus m_pStubDispatchCellSection contains all hot cells at the front of
356         // this blob of data.  By making them last in a grouping of written data we
357         // make sure the hot data is grouped with hot data in the
358         // m_pDelayLoadInfoTableSection sections.
359
360         m_pStubDispatchCellSection = NewVirtualSection(pDataSection, IBCProfiledSection | HotColdSortedRange | StubDispatchDataSection, TARGET_POINTER_SIZE);
361
362         // Earlier we placed the HOT corCompile tables. Now place the cold ones after the stub dispatch cell section. 
363         for (int i=0; i<ZapImportSectionType_Count; i++)
364         {
365             m_pDelayLoadInfoTableSection[ZapImportSectionType_Cold + i] = NewVirtualSection(pDataSection, IBCProfiledSection | ColdRange | DelayLoadInfoTableSection, TARGET_POINTER_SIZE);
366         }
367
368         //
369         // Virtual sections that are moved to .cdata when we have profile data.
370         //
371
372         // This is everyhing that is assumed to be warm in the first strata
373         // of non-profiled scenarios.  MethodTables related to objects etc.
374         m_pPreloadSections[CORCOMPILE_SECTION_WARM] = NewVirtualSection(pDataSection, IBCProfiledSection | WarmRange | EEDataSection, TARGET_POINTER_SIZE);
375
376         m_pPreloadSections[CORCOMPILE_SECTION_RVA_STATICS_COLD] = NewVirtualSection(pDataSection, IBCProfiledSection | ColdRange | RVAStaticsSection);
377
378         // In an ideal world these are cold in both profiled and the first strata
379         // of non-profiled scenarios (i.e. no reflection, etc. )  The sections at the
380         // bottom correspond to further strata of non-profiled scenarios.
381         m_pPreloadSections[CORCOMPILE_SECTION_CLASS_COLD] = NewVirtualSection(pDataSection, IBCProfiledSection | ColdRange | ClassSection, TARGET_POINTER_SIZE);
382         m_pPreloadSections[CORCOMPILE_SECTION_CROSS_DOMAIN_INFO] = NewVirtualSection(pDataSection, IBCUnProfiledSection | ColdRange | CrossDomainInfoSection, TARGET_POINTER_SIZE);
383         m_pPreloadSections[CORCOMPILE_SECTION_METHOD_DESC_COLD] = NewVirtualSection(pDataSection, IBCProfiledSection | ColdRange | MethodDescSection, TARGET_POINTER_SIZE);
384         m_pPreloadSections[CORCOMPILE_SECTION_METHOD_DESC_COLD_WRITEABLE] = NewVirtualSection(pDataSection, IBCProfiledSection | ColdRange | MethodDescWriteableSection, TARGET_POINTER_SIZE);
385         m_pPreloadSections[CORCOMPILE_SECTION_MODULE_COLD] = NewVirtualSection(pDataSection, IBCProfiledSection | ColdRange | ModuleSection, TARGET_POINTER_SIZE);
386         m_pPreloadSections[CORCOMPILE_SECTION_DEBUG_COLD] = NewVirtualSection(pDataSection, IBCUnProfiledSection | ColdRange | DebugSection, TARGET_POINTER_SIZE);
387
388         //
389         // If we're instrumenting allocate a section for writing profile data
390         //
391         if (m_zapper->m_pOpt->m_compilerFlags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_BBINSTR))
392         {
393             m_pInstrumentSection = NewVirtualSection(pDataSection, IBCUnProfiledSection | ColdRange | InstrumentSection, TARGET_POINTER_SIZE);
394         }
395     }
396
397     // No RWX pages in ready to run images
398     if (!IsReadyToRunCompilation())
399     {
400         DWORD access = XDATA_MEM;
401
402 #ifdef FEATURE_LAZY_COW_PAGES
403         if (CLRConfig::GetConfigValue(CLRConfig::INTERNAL_ZapLazyCOWPagesEnabled))
404             access = TEXT_MEM;
405 #endif            
406
407         //
408         // .xdata section
409         //
410         ZapPhysicalSection * pXDataSection  = NewPhysicalSection(".xdata", IMAGE_SCN_CNT_INITIALIZED_DATA | access);
411
412         // Some sections are placed in a sorted order. Hot items are placed first,
413         // then cold items. These sections are marked as HotColdSortedRange since
414         // they are neither completely hot, nor completely cold. 
415         m_pVirtualImportThunkSection        = NewVirtualSection(pXDataSection, IBCProfiledSection | HotColdSortedRange | VirtualImportThunkSection, HELPER_TABLE_ALIGN);
416         m_pExternalMethodThunkSection       = NewVirtualSection(pXDataSection, IBCProfiledSection | HotColdSortedRange | ExternalMethodThunkSection, HELPER_TABLE_ALIGN);
417         m_pHelperTableSection               = NewVirtualSection(pXDataSection, IBCProfiledSection | HotColdSortedRange| HelperTableSection, HELPER_TABLE_ALIGN);
418
419         // hot for writing, i.e. profiling has indicated a write to this item, so at least one write likely per item at some point
420         m_pPreloadSections[CORCOMPILE_SECTION_METHOD_PRECODE_WRITE] = NewVirtualSection(pXDataSection, IBCProfiledSection | HotRange | MethodPrecodeWriteSection, TARGET_POINTER_SIZE);
421         m_pPreloadSections[CORCOMPILE_SECTION_METHOD_PRECODE_HOT] = NewVirtualSection(pXDataSection, IBCProfiledSection | HotRange | MethodPrecodeSection, TARGET_POINTER_SIZE);
422
423         //
424         // cold sections
425         //
426         m_pPreloadSections[CORCOMPILE_SECTION_METHOD_PRECODE_COLD] = NewVirtualSection(pXDataSection, IBCProfiledSection | ColdRange | MethodPrecodeSection, TARGET_POINTER_SIZE);
427         m_pPreloadSections[CORCOMPILE_SECTION_METHOD_PRECODE_COLD_WRITEABLE] = NewVirtualSection(pXDataSection, IBCProfiledSection | ColdRange | MethodPrecodeWriteableSection, TARGET_POINTER_SIZE);
428     }
429
430     {
431         // code:NativeUnwindInfoLookupTable::LookupUnwindInfoForMethod and code:NativeImageJitManager::GetFunctionEntry expects 
432         // sentinel value right after end of .pdata section. 
433         static const DWORD dwRuntimeFunctionSectionSentinel = (DWORD)-1;
434
435
436         //
437         // .text section
438         //
439 #if defined(_TARGET_ARM_)
440         // for ARM, put the resource section at the end if it's very large - this
441         // is because b and bl instructions have a limited distance range of +-16MB
442         // which we should not exceed if we can avoid it.
443         // we draw the limit at 1 MB resource size, somewhat arbitrarily
444         COUNT_T resourceSize;
445         m_ModuleDecoder.GetResources(&resourceSize);
446         BOOL bigResourceSection = resourceSize >= 1024*1024;
447 #endif
448         ZapPhysicalSection * pTextSection = NewPhysicalSection(".text", IMAGE_SCN_CNT_CODE | TEXT_MEM);
449         m_pTextSection = pTextSection;
450
451         // Marked as HotRange since it contains items that are always touched by
452         // the OS during NGEN image loading (i.e. VersionInfo) 
453         m_pWin32ResourceSection = NewVirtualSection(pTextSection, IBCUnProfiledSection | HotRange | Win32ResourcesSection);
454
455         // Marked as a HotRange since it is always touched during Ngen image load. 
456         m_pHeaderSection = NewVirtualSection(pTextSection, IBCUnProfiledSection | HotRange | HeaderSection);
457
458         // Marked as a HotRange since it is always touched during Ngen image binding.
459         m_pMetaDataSection = NewVirtualSection(pTextSection, IBCUnProfiledSection | HotRange | MetadataSection);
460
461         m_pImportTableSection = NewVirtualSection(pTextSection, IBCUnProfiledSection | HotRange | ImportTableSection, sizeof(DWORD));
462
463         m_pDelayLoadInfoDelayListSectionEager = NewVirtualSection(pTextSection, IBCUnProfiledSection | HotRange | DelayLoadInfoDelayListSection, sizeof(DWORD));
464
465         //
466         // GC Info for methods which were profiled hot AND had their GC Info touched during profiling
467         //
468         m_pHotTouchedGCSection = NewVirtualSection(pTextSection, IBCProfiledSection | HotRange | GCInfoSection, sizeof(DWORD));
469
470         m_pLazyHelperSection = NewVirtualSection(pTextSection, IBCUnProfiledSection | HotRange | HelperTableSection, MINIMUM_CODE_ALIGN);
471         m_pLazyHelperSection->SetDefaultFill(DEFAULT_CODE_BUFFER_INIT);
472
473         m_pLazyMethodCallHelperSection = NewVirtualSection(pTextSection, IBCUnProfiledSection | HotRange | HelperTableSection, MINIMUM_CODE_ALIGN);
474         m_pLazyMethodCallHelperSection->SetDefaultFill(DEFAULT_CODE_BUFFER_INIT);
475
476         int codeSectionAlign = DEFAULT_CODE_ALIGN;
477
478         m_pHotCodeSection = NewVirtualSection(pTextSection, IBCProfiledSection | HotRange | CodeSection, codeSectionAlign);
479         m_pHotCodeSection->SetDefaultFill(DEFAULT_CODE_BUFFER_INIT);
480
481 #if defined(WIN64EXCEPTIONS)
482         m_pHotUnwindDataSection = NewVirtualSection(pTextSection, IBCProfiledSection | HotRange | UnwindDataSection, sizeof(DWORD)); // .rdata area
483
484         // All RuntimeFunctionSections have to be together for WIN64EXCEPTIONS
485         m_pHotRuntimeFunctionSection = NewVirtualSection(pTextSection, IBCProfiledSection | HotRange | RuntimeFunctionSection, sizeof(DWORD));  // .pdata area
486         m_pRuntimeFunctionSection = NewVirtualSection(pTextSection, IBCProfiledSection | WarmRange  | ColdRange | RuntimeFunctionSection, sizeof(DWORD));
487         m_pColdRuntimeFunctionSection = NewVirtualSection(pTextSection, IBCProfiledSection | IBCUnProfiledSection | ColdRange | RuntimeFunctionSection, sizeof(DWORD));
488
489         // The following sentinel section is just a padding for RuntimeFunctionSection - Apply same classification 
490         NewVirtualSection(pTextSection, IBCProfiledSection | IBCUnProfiledSection | ColdRange | RuntimeFunctionSection, sizeof(DWORD))
491             ->Place(new (GetHeap()) ZapBlobPtr((PVOID)&dwRuntimeFunctionSectionSentinel, sizeof(DWORD)));
492 #endif  // defined(WIN64EXCEPTIONS)
493
494         m_pStubsSection = NewVirtualSection(pTextSection, IBCProfiledSection | HotColdSortedRange | StubsSection);
495         m_pReadOnlyDataSection = NewVirtualSection(pTextSection, IBCProfiledSection | HotColdSortedRange | ReadonlyDataSection);
496
497         m_pDynamicHelperDataSection = NewVirtualSection(pTextSection, IBCProfiledSection | HotColdSortedRange | ExternalMethodDataSection, sizeof(DWORD));
498         m_pExternalMethodDataSection = NewVirtualSection(pTextSection, IBCProfiledSection | HotColdSortedRange | ExternalMethodDataSection, sizeof(DWORD));
499         m_pStubDispatchDataSection = NewVirtualSection(pTextSection, IBCProfiledSection | HotColdSortedRange | StubDispatchDataSection, sizeof(DWORD));
500
501         m_pHotRuntimeFunctionLookupSection = NewVirtualSection(pTextSection, IBCProfiledSection | HotRange | RuntimeFunctionSection, sizeof(DWORD));
502 #if !defined(WIN64EXCEPTIONS)
503         m_pHotRuntimeFunctionSection = NewVirtualSection(pTextSection, IBCProfiledSection | HotRange | RuntimeFunctionSection, sizeof(DWORD));
504
505         // The following sentinel section is just a padding for RuntimeFunctionSection - Apply same classification 
506         NewVirtualSection(pTextSection, IBCProfiledSection | HotRange | RuntimeFunctionSection, sizeof(DWORD))
507             ->Place(new (GetHeap()) ZapBlobPtr((PVOID)&dwRuntimeFunctionSectionSentinel, sizeof(DWORD)));
508 #endif
509         m_pHotCodeMethodDescsSection = NewVirtualSection(pTextSection, IBCProfiledSection | HotRange | CodeManagerSection, sizeof(DWORD));
510
511         m_pDelayLoadInfoDelayListSectionHot = NewVirtualSection(pTextSection, IBCProfiledSection | HotRange | DelayLoadInfoDelayListSection, sizeof(DWORD));
512
513         //
514         // The hot set of read-only data structures.  Note that read-only data structures are the things that we can (and aggressively do) intern
515         // to share between different owners.  However, this can have a bad interaction with IBC, which performs its ordering optimizations without
516         // knowing that NGen may jumble around layout with interning.  Thankfully, it is a relatively small percentage of the items that are duplicates
517         // (many of them used a great deal to add up to large interning savings).  This means that we can track all of the interned items for which we
518         // actually find any duplicates and put those in a small section.  For the rest, where there wasn't a duplicate in the entire image, we leave the
519         // singleton in its normal place in the READONLY_HOT section, which was selected carefully by IBC.
520         //
521         m_pPreloadSections[CORCOMPILE_SECTION_READONLY_SHARED_HOT] = NewVirtualSection(pTextSection, IBCProfiledSection | HotRange | ReadonlySharedSection, TARGET_POINTER_SIZE);
522         m_pPreloadSections[CORCOMPILE_SECTION_READONLY_HOT] = NewVirtualSection(pTextSection, IBCProfiledSection | HotRange | ReadonlySection, TARGET_POINTER_SIZE);
523
524         //
525         // GC Info for methods which were touched during profiling but didn't explicitly have
526         // their GC Info touched during profiling
527         //
528         m_pHotGCSection = NewVirtualSection(pTextSection, IBCProfiledSection | WarmRange | GCInfoSection, sizeof(DWORD));
529
530 #if !defined(_TARGET_ARM_)
531         // For ARM, put these sections more towards the end because bl/b instructions have limited diplacement
532
533         // IL
534         m_pILSection  = NewVirtualSection(pTextSection, IBCProfiledSection | HotColdSortedRange | ILSection, sizeof(DWORD));
535
536         //ILMetadata/Resources sections are reported as a statically known warm ranges for now.
537         m_pILMetaDataSection = NewVirtualSection(pTextSection, IBCProfiledSection | HotColdSortedRange | ILMetadataSection, sizeof(DWORD));
538 #endif  // _TARGET_ARM_
539
540 #if defined(_TARGET_ARM_)
541         if (!bigResourceSection) // for ARM, put the resource section at the end if it's very large - see comment above
542 #endif
543             m_pResourcesSection = NewVirtualSection(pTextSection, IBCUnProfiledSection | WarmRange | ResourcesSection);
544
545         //
546         // Allocate the unprofiled code section and code manager nibble map here
547         //
548         m_pCodeSection = NewVirtualSection(pTextSection, IBCProfiledSection | WarmRange | ColdRange | CodeSection, codeSectionAlign);
549         m_pCodeSection->SetDefaultFill(DEFAULT_CODE_BUFFER_INIT);
550
551         m_pRuntimeFunctionLookupSection = NewVirtualSection(pTextSection, IBCProfiledSection | WarmRange | ColdRange | RuntimeFunctionSection, sizeof(DWORD));
552 #if !defined(WIN64EXCEPTIONS)
553         m_pRuntimeFunctionSection = NewVirtualSection(pTextSection, IBCProfiledSection | WarmRange  | ColdRange | RuntimeFunctionSection, sizeof(DWORD));
554
555         // The following sentinel section is just a padding for RuntimeFunctionSection - Apply same classification 
556         NewVirtualSection(pTextSection, IBCProfiledSection | WarmRange  | ColdRange | RuntimeFunctionSection, sizeof(DWORD))
557             ->Place(new (GetHeap()) ZapBlobPtr((PVOID)&dwRuntimeFunctionSectionSentinel, sizeof(DWORD)));
558 #endif
559         m_pCodeMethodDescsSection = NewVirtualSection(pTextSection, IBCProfiledSection | WarmRange | ColdRange | CodeHeaderSection,sizeof(DWORD));
560
561 #ifdef FEATURE_READYTORUN_COMPILER
562         if (IsReadyToRunCompilation())
563         {
564             m_pAvailableTypesSection = NewVirtualSection(pTextSection, IBCUnProfiledSection | WarmRange | ReadonlySection);
565             m_pAttributePresenceSection = NewVirtualSection(pTextSection, IBCUnProfiledSection | WarmRange | ReadonlyDataSection, 16/* Must be 16 byte aligned */);
566         }
567 #endif    
568
569 #if defined(WIN64EXCEPTIONS)
570         m_pUnwindDataSection = NewVirtualSection(pTextSection, IBCProfiledSection | WarmRange | ColdRange | UnwindDataSection, sizeof(DWORD));
571 #endif // defined(WIN64EXCEPTIONS)
572
573         m_pPreloadSections[CORCOMPILE_SECTION_READONLY_WARM] = NewVirtualSection(pTextSection, IBCProfiledSection | WarmRange | ReadonlySection, TARGET_POINTER_SIZE);
574         m_pPreloadSections[CORCOMPILE_SECTION_READONLY_VCHUNKS] = NewVirtualSection(pTextSection, IBCProfiledSection | WarmRange | ReadonlySection, TARGET_POINTER_SIZE);
575         m_pPreloadSections[CORCOMPILE_SECTION_READONLY_DICTIONARY] = NewVirtualSection(pTextSection, IBCProfiledSection | WarmRange | ReadonlySection, TARGET_POINTER_SIZE);
576
577         //
578         // GC Info for methods which were not touched in profiling
579         //
580         m_pGCSection = NewVirtualSection(pTextSection, IBCProfiledSection | ColdRange | GCInfoSection, sizeof(DWORD));
581
582         m_pDelayLoadInfoDelayListSectionCold = NewVirtualSection(pTextSection, IBCProfiledSection | ColdRange | DelayLoadInfoDelayListSection, sizeof(DWORD));
583
584         m_pPreloadSections[CORCOMPILE_SECTION_READONLY_COLD] = NewVirtualSection(pTextSection, IBCProfiledSection | ColdRange | ReadonlySection, TARGET_POINTER_SIZE);
585
586         //
587         // Allocate the cold code section near the end of the image
588         //
589         m_pColdCodeSection = NewVirtualSection(pTextSection, IBCProfiledSection | IBCUnProfiledSection | ColdRange | CodeSection, codeSectionAlign);
590         m_pColdCodeSection->SetDefaultFill(DEFAULT_CODE_BUFFER_INIT);
591
592 #if defined(_TARGET_ARM_)
593         // For ARM, put these sections more towards the end because bl/b instructions have limited diplacement
594
595         // IL
596         m_pILSection  = NewVirtualSection(pTextSection, IBCProfiledSection | HotColdSortedRange | ILSection, sizeof(DWORD));
597
598         //ILMetadata/Resources sections are reported as a statically known warm ranges for now.
599         m_pILMetaDataSection = NewVirtualSection(pTextSection, IBCProfiledSection | HotColdSortedRange | ILMetadataSection, sizeof(DWORD));
600
601         if (bigResourceSection) // for ARM, put the resource section at the end if it's very large - see comment above
602             m_pResourcesSection = NewVirtualSection(pTextSection, IBCUnProfiledSection | WarmRange | ResourcesSection);
603 #endif // _TARGET_ARM_
604         m_pColdCodeMapSection = NewVirtualSection(pTextSection, IBCProfiledSection | IBCUnProfiledSection | ColdRange | CodeManagerSection, sizeof(DWORD));
605
606 #if !defined(WIN64EXCEPTIONS)
607         m_pColdRuntimeFunctionSection = NewVirtualSection(pTextSection, IBCProfiledSection | IBCUnProfiledSection | ColdRange | RuntimeFunctionSection, sizeof(DWORD));
608
609         // The following sentinel section is just a padding for RuntimeFunctionSection - Apply same classification 
610         NewVirtualSection(pTextSection, IBCProfiledSection | IBCUnProfiledSection | ColdRange | RuntimeFunctionSection, sizeof(DWORD))
611             ->Place(new (GetHeap()) ZapBlobPtr((PVOID)&dwRuntimeFunctionSectionSentinel, sizeof(DWORD)));
612 #endif
613
614 #if defined(WIN64EXCEPTIONS)
615         m_pColdUnwindDataSection = NewVirtualSection(pTextSection, IBCProfiledSection | IBCUnProfiledSection | ColdRange | UnwindDataSection, sizeof(DWORD));
616 #endif // defined(WIN64EXCEPTIONS)
617
618         //
619         // Allocate space for compressed LookupMaps (ridmaps). This needs to come after the .data physical
620         // section (which is currently true for the .text section) and late enough in the .text section to be
621         // after any structure referenced by the LookupMap (current MethodTables and MethodDescs). This is a
622         // hard requirement since the compression algorithm requires that all referenced data structures have
623         // been laid out by the time we come to lay out the compressed nodes.
624         //
625         m_pPreloadSections[CORCOMPILE_SECTION_COMPRESSED_MAPS] = NewVirtualSection(pTextSection, IBCProfiledSection | ColdRange | CompressedMapsSection, sizeof(DWORD));
626
627         m_pExceptionSection = NewVirtualSection(pTextSection, IBCProfiledSection | HotColdSortedRange | ExceptionSection, sizeof(DWORD));
628
629         //
630         // Debug info is sometimes used during exception handling to build stacktrace
631         //
632         m_pDebugSection = NewVirtualSection(pTextSection, IBCUnProfiledSection | ColdRange | DebugSection, sizeof(DWORD));
633     }
634
635     {
636         //
637         // .reloc section
638         //
639
640         ZapPhysicalSection * pRelocSection = NewPhysicalSection(".reloc", IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_DISCARDABLE | IMAGE_SCN_MEM_READ);
641
642         // .reloc section is always read by the OS when the image is opted in ASLR
643         // (Vista+ default behavior). 
644         m_pBaseRelocsSection = NewVirtualSection(pRelocSection, IBCUnProfiledSection | HotRange | BaseRelocsSection);
645
646     }
647 }
648
649 void ZapImage::Preallocate()
650 {
651     COUNT_T cbILImage = m_ModuleDecoder.GetSize();
652
653     // Curb the estimate to handle corner cases gracefuly
654     cbILImage = min(cbILImage, 50000000);
655
656     PREALLOCATE_HASHTABLE(ZapImage::m_CompiledMethods, 0.0050, cbILImage);
657     PREALLOCATE_HASHTABLE(ZapImage::m_ClassLayoutOrder, 0.0003, cbILImage);
658
659     //
660     // Preallocation of auxiliary tables in alphabetical order
661     //
662     m_pImportTable->Preallocate(cbILImage);
663     m_pInnerPtrs->Preallocate(cbILImage);
664     m_pMethodEntryPoints->Preallocate(cbILImage);
665     m_pWrappers->Preallocate(cbILImage);
666
667     if (m_pILMetaData != NULL)
668         m_pILMetaData->Preallocate(cbILImage);
669     m_pGCInfoTable->Preallocate(cbILImage);
670 #ifdef WIN64EXCEPTIONS
671     m_pUnwindDataTable->Preallocate(cbILImage);
672 #endif // WIN64EXCEPTIONS
673     m_pDebugInfoTable->Preallocate(cbILImage);
674 }
675
676 void ZapImage::SetVersionInfo(CORCOMPILE_VERSION_INFO * pVersionInfo)
677 {
678     m_pVersionInfo = new (GetHeap()) ZapVersionInfo(pVersionInfo);
679     m_pHeaderSection->Place(m_pVersionInfo);
680 }
681
682 void ZapImage::SetDependencies(CORCOMPILE_DEPENDENCY *pDependencies, DWORD cDependencies)
683 {
684     m_pDependencies = new (GetHeap()) ZapDependencies(pDependencies, cDependencies);
685     m_pHeaderSection->Place(m_pDependencies);
686 }
687
688 void ZapImage::SetPdbFileName(const SString &strFileName)
689 {
690     m_pdbFileName.Set(strFileName);
691 }
692
693 #ifdef WIN64EXCEPTIONS
694 void ZapImage::SetRuntimeFunctionsDirectoryEntry()
695 {
696     //
697     // Runtime functions span multiple virtual sections and so there is no natural ZapNode * to cover them all.
698     // Create dummy ZapNode * that covers them all for IMAGE_DIRECTORY_ENTRY_EXCEPTION directory entry.
699     //
700     ZapVirtualSection * rgRuntimeFunctionSections[] = {
701         m_pHotRuntimeFunctionSection,
702         m_pRuntimeFunctionSection,
703         m_pColdRuntimeFunctionSection
704     };
705
706     DWORD dwTotalSize = 0, dwStartRVA = (DWORD)-1, dwEndRVA = 0;
707
708     for (size_t i = 0; i < _countof(rgRuntimeFunctionSections); i++)
709     {
710         ZapVirtualSection * pSection = rgRuntimeFunctionSections[i];
711
712         DWORD dwSize = pSection->GetSize();
713         if (dwSize == 0)
714             continue;
715
716         DWORD dwRVA = pSection->GetRVA();
717
718         dwTotalSize += dwSize;
719
720         dwStartRVA = min(dwStartRVA, dwRVA);
721         dwEndRVA = max(dwEndRVA, dwRVA + dwSize);
722     }
723
724     if (dwTotalSize != 0)
725     {
726         // Verify that there are no holes between the sections
727         _ASSERTE(dwStartRVA + dwTotalSize == dwEndRVA);
728
729         ZapNode * pAllRuntimeFunctionSections = new (GetHeap()) ZapDummyNode(dwTotalSize);
730         pAllRuntimeFunctionSections->SetRVA(dwStartRVA);
731
732         // Write the address of the sorted pdata to the optionalHeader.DataDirectory
733         SetDirectoryEntry(IMAGE_DIRECTORY_ENTRY_EXCEPTION, pAllRuntimeFunctionSections);
734     }
735 }
736 #endif // WIN64EXCEPTIONS
737
738 // Assign RVAs to all ZapNodes
739 void ZapImage::ComputeRVAs()
740 {
741     ZapWriter::ComputeRVAs();
742
743     if (!IsReadyToRunCompilation())
744     {
745         m_pMethodEntryPoints->Resolve();
746         m_pWrappers->Resolve();
747     }
748
749     m_pInnerPtrs->Resolve();
750
751 #ifdef WIN64EXCEPTIONS
752     SetRuntimeFunctionsDirectoryEntry();
753 #endif
754
755 #if defined(_DEBUG) 
756 #ifdef FEATURE_SYMDIFF
757     if (CLRConfig::GetConfigValue(CLRConfig::INTERNAL_SymDiffDump))
758     {
759         COUNT_T curMethod = 0;
760         COUNT_T numMethods = m_MethodCompilationOrder.GetCount();
761
762         for (; curMethod < numMethods; curMethod++)
763         {
764             bool fCold = false;
765             //if(curMethod >= m_iUntrainedMethod) fCold = true;
766                 
767             ZapMethodHeader * pMethod = m_MethodCompilationOrder[curMethod];
768
769             ZapBlobWithRelocs * pCode = fCold ? pMethod->m_pColdCode : pMethod->m_pCode;
770             if (pCode == NULL)
771             {            
772                 continue;
773             }
774             CORINFO_METHOD_HANDLE handle = pMethod->GetHandle();
775             mdMethodDef token;
776             GetCompileInfo()->GetMethodDef(handle, &token);
777             GetSvcLogger()->Printf(W("(EntryPointRVAMap (MethodToken %0X) (RVA %0X) (SIZE %0X))\n"), token, pCode->GetRVA(), pCode->GetSize()); 
778         }
779
780     }
781 #endif // FEATURE_SYMDIFF 
782 #endif //_DEBUG
783 }
784
785 class ZapFileStream : public IStream
786 {
787     HANDLE  m_hFile;
788     MD5 m_hasher;
789
790 public:
791     ZapFileStream()
792         : m_hFile(INVALID_HANDLE_VALUE)
793     {
794         m_hasher.Init();
795     }
796
797     ~ZapFileStream()
798     {
799         Close();
800     }
801
802     void SetHandle(HANDLE hFile)
803     {
804         _ASSERTE(m_hFile == INVALID_HANDLE_VALUE);
805         m_hFile = hFile;
806     }
807
808     // IUnknown methods:
809     STDMETHODIMP_(ULONG) AddRef()
810     {
811         return 1;
812     }
813
814     STDMETHODIMP_(ULONG) Release()
815     {
816         return 1;
817     }
818
819     STDMETHODIMP QueryInterface(REFIID riid, LPVOID *ppv)
820     {
821         HRESULT hr = S_OK;
822         if (IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_IStream)) {
823             *ppv = static_cast<IStream *>(this);
824         }
825         else {
826             hr = E_NOINTERFACE;
827         }
828         return hr;
829     }
830
831     // ISequentialStream methods:
832     STDMETHODIMP Read(void *pv, ULONG cb, ULONG *pcbRead)
833     {
834         _ASSERTE(false);
835         return E_NOTIMPL;
836     }
837
838     STDMETHODIMP Write(void const *pv, ULONG cb, ULONG *pcbWritten)
839     {
840         HRESULT hr = S_OK;
841
842         _ASSERTE(m_hFile != INVALID_HANDLE_VALUE);
843
844         m_hasher.HashMore(pv, cb);
845
846         // We are calling with lpOverlapped == NULL so pcbWritten has to be present
847         // to prevent crashes in Win7 and below.
848         _ASSERTE(pcbWritten);
849
850         if (!::WriteFile(m_hFile, pv, cb, pcbWritten, NULL))
851         {
852             hr = HRESULT_FROM_GetLastError();
853             goto Exit;
854         }
855
856     Exit:
857         return hr;
858     }
859
860     // IStream methods:
861     STDMETHODIMP Seek(LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition)
862     {
863         HRESULT hr = S_OK;        
864
865         _ASSERTE(m_hFile != INVALID_HANDLE_VALUE);
866
867         DWORD dwFileOrigin;
868         switch (dwOrigin) {
869             case STREAM_SEEK_SET:
870                 dwFileOrigin = FILE_BEGIN;
871                 break;
872                 
873             case STREAM_SEEK_CUR:
874                 dwFileOrigin = FILE_CURRENT;
875                 break;
876                 
877             case STREAM_SEEK_END:
878                 dwFileOrigin = FILE_END;
879                 break;
880                 
881             default:
882                 hr = E_UNEXPECTED;
883                 goto Exit;
884         }
885         if (!::SetFilePointerEx(m_hFile, dlibMove, (LARGE_INTEGER *)plibNewPosition, dwFileOrigin))
886         {
887             hr = HRESULT_FROM_GetLastError();
888             goto Exit;
889         }
890
891     Exit:
892         return hr;
893     }
894
895     STDMETHODIMP SetSize(ULARGE_INTEGER libNewSize)
896     {
897         HRESULT hr = S_OK;
898
899         _ASSERTE(m_hFile != INVALID_HANDLE_VALUE);
900
901         hr = Seek(*(LARGE_INTEGER *)&libNewSize, FILE_BEGIN, NULL);
902         if (FAILED(hr))
903         {
904             goto Exit;
905         }
906
907         if (!::SetEndOfFile(m_hFile))
908         {
909             hr = HRESULT_FROM_GetLastError();
910             goto Exit;
911         }
912
913     Exit:
914         return hr;
915     }
916
917     STDMETHODIMP CopyTo(IStream *pstm, ULARGE_INTEGER cb, ULARGE_INTEGER *pcbRead, ULARGE_INTEGER *pcbWritten)
918     {
919         _ASSERTE(false);
920         return E_NOTIMPL;
921     }
922
923     STDMETHODIMP Commit(DWORD grfCommitFlags)
924     {
925         _ASSERTE(false);
926         return E_NOTIMPL;
927     }
928
929     STDMETHODIMP Revert()
930     {
931         _ASSERTE(false);
932         return E_NOTIMPL;
933     }
934
935     STDMETHODIMP LockRegion(ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType)
936     {
937         _ASSERTE(false);
938         return E_NOTIMPL;
939     }
940
941     STDMETHODIMP UnlockRegion(ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType)
942     {
943         _ASSERTE(false);
944         return E_NOTIMPL;
945     }
946
947     STDMETHODIMP Stat(STATSTG *pstatstg, DWORD grfStatFlag)
948     {
949         _ASSERTE(false);
950         return E_NOTIMPL;
951     }
952
953     STDMETHODIMP Clone(IStream **ppIStream)
954     {
955         _ASSERTE(false);
956         return E_NOTIMPL;
957     }
958
959     HRESULT Close()
960     {
961         HRESULT hr = S_OK;
962
963         HANDLE hFile = m_hFile;
964         if (hFile != INVALID_HANDLE_VALUE)
965         {
966             m_hFile = INVALID_HANDLE_VALUE;
967
968             if (!::CloseHandle(hFile))
969             {
970                 hr = HRESULT_FROM_GetLastError();
971                 goto Exit;
972             }
973         }
974
975     Exit:
976         return hr;
977     }
978
979     void SuppressClose()
980     {
981         m_hFile = INVALID_HANDLE_VALUE;
982     }
983
984     void GetHash(MD5HASHDATA* pHash)
985     {
986         m_hasher.GetHashValue(pHash);
987     }
988 };
989
990 HANDLE ZapImage::GenerateFile(LPCWSTR wszOutputFileName, CORCOMPILE_NGEN_SIGNATURE * pNativeImageSig)
991 {
992     ZapFileStream outputStream;
993
994     HANDLE hFile = WszCreateFile(wszOutputFileName,
995                         GENERIC_READ | GENERIC_WRITE,
996                         FILE_SHARE_READ | FILE_SHARE_DELETE,
997                         NULL,
998                         CREATE_ALWAYS,
999                         FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,
1000                         NULL);
1001
1002     if (hFile == INVALID_HANDLE_VALUE)
1003         ThrowLastError();
1004
1005     outputStream.SetHandle(hFile);
1006
1007     Save(&outputStream);
1008
1009     LARGE_INTEGER filePos;
1010
1011     if (m_pNativeHeader != NULL)
1012     {
1013         // Write back the updated CORCOMPILE_HEADER (relocs and guid is not correct the first time around)
1014         filePos.QuadPart = m_pTextSection->GetFilePos() + 
1015             (m_pNativeHeader->GetRVA() - m_pTextSection->GetRVA());
1016         IfFailThrow(outputStream.Seek(filePos, STREAM_SEEK_SET, NULL));
1017         m_pNativeHeader->Save(this);
1018         FlushWriter();
1019     }
1020
1021     GUID signature = {0};
1022
1023     static_assert_no_msg(sizeof(GUID) == sizeof(MD5HASHDATA));
1024     outputStream.GetHash((MD5HASHDATA*)&signature);
1025
1026     {    
1027         // Write the debug directory entry for the NGEN PDB
1028         RSDS rsds = {0};
1029
1030         rsds.magic = VAL32(0x53445352); // "SDSR";
1031         rsds.age = 1;
1032         // our PDB signature will be the same as our NGEN signature.  
1033         // However we want the printed version of the GUID to be be the same as the
1034         // byte dump of the signature so we swap bytes to make this work.  
1035         // 
1036         // * See code:CCorSvcMgr::CreatePdb for where this is used.
1037         BYTE* asBytes = (BYTE*) &signature;
1038         rsds.signature.Data1 = ((asBytes[0] * 256 + asBytes[1]) * 256 + asBytes[2]) * 256 + asBytes[3];
1039         rsds.signature.Data2 = asBytes[4] * 256 + asBytes[5];
1040         rsds.signature.Data3 = asBytes[6] * 256 + asBytes[7];
1041         memcpy(&rsds.signature.Data4, &asBytes[8], 8);
1042
1043         _ASSERTE(!m_pdbFileName.IsEmpty());
1044         ZeroMemory(&rsds.path[0], sizeof(rsds.path));
1045         if (WideCharToMultiByte(CP_UTF8, 
1046                                 0, 
1047                                 m_pdbFileName.GetUnicode(),
1048                                 m_pdbFileName.GetCount(), 
1049                                 &rsds.path[0], 
1050                                 sizeof(rsds.path) - 1, // -1 to keep the buffer zero terminated
1051                                 NULL, 
1052                                 NULL) == 0)
1053             ThrowHR(E_FAIL);
1054         
1055         ULONG cbWritten = 0;
1056         filePos.QuadPart = m_pTextSection->GetFilePos() + (m_pNGenPdbDebugData->GetRVA() - m_pTextSection->GetRVA());
1057         IfFailThrow(outputStream.Seek(filePos, STREAM_SEEK_SET, NULL));
1058         IfFailThrow(outputStream.Write(&rsds, sizeof rsds, &cbWritten));
1059     }
1060
1061     if (m_pVersionInfo != NULL)
1062     {
1063         ULONG cbWritten;
1064
1065         filePos.QuadPart = m_pTextSection->GetFilePos() + 
1066             (m_pVersionInfo->GetRVA() - m_pTextSection->GetRVA()) + 
1067             offsetof(CORCOMPILE_VERSION_INFO, signature);
1068         IfFailThrow(outputStream.Seek(filePos, STREAM_SEEK_SET, NULL));
1069         IfFailThrow(outputStream.Write(&signature, sizeof(signature), &cbWritten));
1070
1071         if (pNativeImageSig != NULL)
1072             *pNativeImageSig = signature;
1073     }
1074     else
1075     {
1076         _ASSERTE(pNativeImageSig == NULL);
1077     }
1078
1079     outputStream.SuppressClose();
1080     return hFile;
1081 }
1082
1083
1084 HANDLE ZapImage::SaveImage(LPCWSTR wszOutputFileName, LPCWSTR wszDllPath, CORCOMPILE_NGEN_SIGNATURE * pNativeImageSig)
1085 {
1086     if(!IsReadyToRunCompilation() || IsLargeVersionBubbleEnabled())
1087     {
1088         OutputManifestMetadata();
1089     }
1090
1091     OutputTables();
1092
1093     // Create a empty export table.  This makes tools like symchk not think
1094     // that native images are resoure-only DLLs.  It is important to NOT
1095     // be a resource-only DLL because those DLL's PDBS are not put up on the
1096     // symbol server and we want NEN PDBS to be placed there.  
1097     ZapPEExports* exports = new(GetHeap()) ZapPEExports(wszDllPath);
1098     m_pDebugSection->Place(exports);
1099     SetDirectoryEntry(IMAGE_DIRECTORY_ENTRY_EXPORT, exports);
1100     
1101     ComputeRVAs();
1102
1103     if (!IsReadyToRunCompilation())
1104     {
1105         m_pPreloader->FixupRVAs();
1106     }
1107
1108     HANDLE hFile = GenerateFile(wszOutputFileName, pNativeImageSig);
1109
1110     if (m_zapper->m_pOpt->m_verbose)
1111     {
1112         PrintStats(wszOutputFileName);
1113     }
1114
1115     return hFile;
1116 }
1117
1118 void ZapImage::PrintStats(LPCWSTR wszOutputFileName)
1119 {
1120 #define ACCUM_SIZE(dest, src) if( src != NULL ) dest+= src->GetSize()
1121     ACCUM_SIZE(m_stats->m_gcInfoSize, m_pHotTouchedGCSection);
1122     ACCUM_SIZE(m_stats->m_gcInfoSize, m_pHotGCSection);
1123     ACCUM_SIZE(m_stats->m_gcInfoSize, m_pGCSection);
1124 #if defined(WIN64EXCEPTIONS)
1125     ACCUM_SIZE(m_stats->m_unwindInfoSize, m_pUnwindDataSection);
1126     ACCUM_SIZE(m_stats->m_unwindInfoSize, m_pHotRuntimeFunctionSection);
1127     ACCUM_SIZE(m_stats->m_unwindInfoSize, m_pRuntimeFunctionSection);
1128     ACCUM_SIZE(m_stats->m_unwindInfoSize, m_pColdRuntimeFunctionSection);
1129 #endif // defined(WIN64EXCEPTIONS)
1130
1131     //
1132     // Get the size of the input & output files
1133     //
1134
1135     {
1136         WIN32_FIND_DATA inputData;
1137         FindHandleHolder inputHandle = WszFindFirstFile(m_pModuleFileName, &inputData);
1138         if (inputHandle != INVALID_HANDLE_VALUE)
1139             m_stats->m_inputFileSize = inputData.nFileSizeLow;
1140     }
1141
1142     {
1143         WIN32_FIND_DATA outputData;
1144         FindHandleHolder outputHandle = WszFindFirstFile(wszOutputFileName, &outputData);
1145         if (outputHandle != INVALID_HANDLE_VALUE)
1146             m_stats->m_outputFileSize = outputData.nFileSizeLow;
1147     }
1148
1149     ACCUM_SIZE(m_stats->m_metadataSize, m_pAssemblyMetaData);
1150
1151     DWORD dwPreloadSize = 0;
1152     for (int iSection = 0; iSection < CORCOMPILE_SECTION_COUNT; iSection++)
1153         ACCUM_SIZE(dwPreloadSize, m_pPreloadSections[iSection]);
1154     m_stats->m_preloadImageSize = dwPreloadSize;
1155
1156     ACCUM_SIZE(m_stats->m_hotCodeMgrSize, m_pHotCodeMethodDescsSection);
1157     ACCUM_SIZE(m_stats->m_unprofiledCodeMgrSize, m_pCodeMethodDescsSection);
1158     ACCUM_SIZE(m_stats->m_coldCodeMgrSize, m_pHotRuntimeFunctionLookupSection);
1159
1160     ACCUM_SIZE(m_stats->m_eeInfoTableSize, m_pEEInfoTable);
1161     ACCUM_SIZE(m_stats->m_helperTableSize, m_pHelperTableSection);
1162     ACCUM_SIZE(m_stats->m_dynamicInfoTableSize, m_pImportSectionsTable);
1163
1164     ACCUM_SIZE(m_stats->m_dynamicInfoDelayListSize, m_pDelayLoadInfoDelayListSectionEager);
1165     ACCUM_SIZE(m_stats->m_dynamicInfoDelayListSize, m_pDelayLoadInfoDelayListSectionHot);
1166     ACCUM_SIZE(m_stats->m_dynamicInfoDelayListSize, m_pDelayLoadInfoDelayListSectionCold);
1167
1168     ACCUM_SIZE(m_stats->m_debuggingTableSize, m_pDebugSection);
1169     ACCUM_SIZE(m_stats->m_headerSectionSize, m_pGCSection);
1170     ACCUM_SIZE(m_stats->m_codeSectionSize, m_pHotCodeSection);
1171     ACCUM_SIZE(m_stats->m_coldCodeSectionSize, m_pColdCodeSection);
1172     ACCUM_SIZE(m_stats->m_exceptionSectionSize, m_pExceptionSection);
1173     ACCUM_SIZE(m_stats->m_readOnlyDataSectionSize, m_pReadOnlyDataSection);
1174     ACCUM_SIZE(m_stats->m_relocSectionSize, m_pBaseRelocsSection);
1175     ACCUM_SIZE(m_stats->m_ILMetadataSize, m_pILMetaData);
1176     ACCUM_SIZE(m_stats->m_virtualImportThunkSize, m_pVirtualImportThunkSection);
1177     ACCUM_SIZE(m_stats->m_externalMethodThunkSize, m_pExternalMethodThunkSection);
1178     ACCUM_SIZE(m_stats->m_externalMethodDataSize, m_pExternalMethodDataSection);
1179 #undef ACCUM_SIZE
1180
1181     if (m_stats->m_failedMethods)
1182         m_zapper->Warning(W("Warning: %d methods (%d%%) could not be compiled.\n"),
1183                           m_stats->m_failedMethods, (m_stats->m_failedMethods*100) / m_stats->m_methods);
1184     if (m_stats->m_failedILStubs)
1185         m_zapper->Warning(W("Warning: %d IL STUB methods could not be compiled.\n"),
1186                           m_stats->m_failedMethods);
1187     m_stats->PrintStats();
1188 }
1189
1190 // Align native images to 64K
1191 const SIZE_T BASE_ADDRESS_ALIGNMENT  = 0xffff;
1192 const double CODE_EXPANSION_FACTOR   =  3.6;
1193
1194 void ZapImage::CalculateZapBaseAddress()
1195 {
1196     static SIZE_T nextBaseAddressForMultiModule;
1197
1198     SIZE_T baseAddress = 0;
1199
1200     {
1201         // Read the actual preferred base address from the disk
1202
1203         // Note that we are reopening the file here. We are not guaranteed to get the same file.
1204         // The worst thing that can happen is that we will read a bogus preferred base address from the file.
1205         HandleHolder hFile(WszCreateFile(m_pModuleFileName,
1206                                             GENERIC_READ,
1207                                             FILE_SHARE_READ|FILE_SHARE_DELETE,
1208                                             NULL,
1209                                             OPEN_EXISTING,
1210                                             FILE_ATTRIBUTE_NORMAL,
1211                                             NULL));
1212         if (hFile == INVALID_HANDLE_VALUE)
1213             ThrowLastError();
1214
1215         HandleHolder hFileMap(WszCreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL));
1216         if (hFileMap == NULL)
1217             ThrowLastError();
1218
1219         MapViewHolder base(MapViewOfFile(hFileMap, FILE_MAP_READ, 0, 0, 0));
1220         if (base == NULL)
1221             ThrowLastError();
1222     
1223         DWORD dwFileLen = SafeGetFileSize(hFile, 0);
1224         if (dwFileLen == INVALID_FILE_SIZE)
1225             ThrowLastError();
1226
1227         PEDecoder peFlat((void *)base, (COUNT_T)dwFileLen);
1228
1229         baseAddress = (SIZE_T) peFlat.GetPreferredBase();
1230     }
1231
1232     // See if the header has the linker's default preferred base address
1233     if (baseAddress == (SIZE_T) 0x00400000)
1234     {
1235         if (m_fManifestModule)
1236         {
1237             // Set the base address for the main assembly with the manifest
1238         
1239             if (!m_ModuleDecoder.IsDll())
1240             {
1241 #if defined(_TARGET_X86_)
1242                 // We use 30000000 for an exe
1243                 baseAddress = 0x30000000;
1244 #elif defined(_TARGET_64BIT_)
1245                 // We use 04000000 for an exe
1246                 // which is remapped to 0x642`88000000 on x64
1247                 baseAddress = 0x04000000;
1248 #endif
1249             }
1250             else
1251             {
1252 #if defined(_TARGET_X86_)
1253                 // We start a 31000000 for the main assembly with the manifest
1254                 baseAddress = 0x31000000;
1255 #elif defined(_TARGET_64BIT_)
1256                 // We start a 05000000 for the main assembly with the manifest
1257                 // which is remapped to 0x642`8A000000 on x64
1258                 baseAddress = 0x05000000;
1259 #endif
1260             }
1261         }
1262         else // is dependent assembly of a multi-module assembly
1263         {
1264             // Set the base address for a dependant multi module assembly
1265                 
1266             // We should have already set the nextBaseAddressForMultiModule
1267             // when we compiled the manifest module
1268             _ASSERTE(nextBaseAddressForMultiModule != 0);
1269             baseAddress = nextBaseAddressForMultiModule;
1270         }
1271     }
1272     else 
1273     {
1274         //
1275         // For some assemblies we have to move the ngen image base address up
1276         // past the end of IL image so that that we don't have a conflict.
1277         //
1278         // CoreCLR currently always loads both the IL and the native image, so
1279         // move the native image out of the way.
1280         {
1281             baseAddress += m_ModuleDecoder.GetVirtualSize();
1282         }
1283     }
1284
1285     if (m_zapper->GetCustomBaseAddress() != 0)
1286     {
1287         //set baseAddress here from crossgen options
1288         baseAddress = m_zapper->GetCustomBaseAddress();
1289     }
1290
1291     // Round to a multiple of 64K
1292     // 64K is the allocation granularity of VirtualAlloc. (Officially this number is not a constant -
1293     // we should be querying the system for its allocation granularity, but we do this all over the place
1294     // currently.)
1295
1296     baseAddress = (baseAddress + BASE_ADDRESS_ALIGNMENT) & ~BASE_ADDRESS_ALIGNMENT;
1297
1298     //
1299     // Calculate the nextBaseAddressForMultiModule
1300     //
1301     SIZE_T tempBaseAddress = baseAddress;
1302     tempBaseAddress += (SIZE_T) (CODE_EXPANSION_FACTOR * (double) m_ModuleDecoder.GetVirtualSize());
1303     tempBaseAddress += BASE_ADDRESS_ALIGNMENT;
1304     tempBaseAddress = (tempBaseAddress + BASE_ADDRESS_ALIGNMENT) & ~BASE_ADDRESS_ALIGNMENT;
1305     
1306     nextBaseAddressForMultiModule = tempBaseAddress;
1307
1308     //
1309     // Now we remap the 32-bit address range used for x86 and PE32 images into thre
1310     // upper address range used on 64-bit platforms
1311     //
1312 #if USE_UPPER_ADDRESS
1313 #if defined(_TARGET_64BIT_)
1314     if (baseAddress < 0x80000000)
1315     {
1316         if (baseAddress < 0x40000000)
1317             baseAddress += 0x40000000; // We map [00000000..3fffffff] to [642'80000000..642'ffffffff]
1318         else
1319             baseAddress -= 0x40000000; // We map [40000000..7fffffff] to [642'00000000..642'7fffffff]
1320
1321         baseAddress *= UPPER_ADDRESS_MAPPING_FACTOR;
1322         baseAddress += CLR_UPPER_ADDRESS_MIN;
1323     }
1324 #endif
1325 #endif
1326
1327
1328     // Apply the calculated base address.
1329     SetBaseAddress(baseAddress);
1330
1331     m_NativeBaseAddress = baseAddress;
1332 }
1333
1334 void ZapImage::Open(CORINFO_MODULE_HANDLE hModule,
1335                         IMetaDataAssemblyEmit *pEmit)
1336 {
1337     m_hModule   = hModule;
1338     m_fManifestModule = (hModule == m_zapper->m_pEECompileInfo->GetAssemblyModule(m_zapper->m_hAssembly));
1339
1340     m_ModuleDecoder = *m_zapper->m_pEECompileInfo->GetModuleDecoder(hModule);
1341
1342
1343     //
1344     // Get file name, and base address from module
1345     //
1346
1347     StackSString moduleFileName;
1348     m_zapper->m_pEECompileInfo->GetModuleFileName(hModule, moduleFileName);
1349
1350     DWORD fileNameLength = moduleFileName.GetCount();
1351     m_pModuleFileName = new WCHAR[fileNameLength+1];
1352     wcscpy_s(m_pModuleFileName, fileNameLength+1, moduleFileName.GetUnicode());
1353
1354     //
1355     // Load the IBC Profile data for the assembly if it exists
1356     // 
1357     LoadProfileData();
1358
1359     //
1360     // Get metadata of module to be compiled
1361     //
1362     m_pMDImport = m_zapper->m_pEECompileInfo->GetModuleMetaDataImport(m_hModule);
1363     _ASSERTE(m_pMDImport != NULL);
1364
1365     //
1366     // Open new assembly metadata data for writing.  We may not use it,
1367     // if so we'll just discard it at the end.
1368     //
1369     if (pEmit != NULL)
1370     {
1371         pEmit->AddRef();
1372         m_pAssemblyEmit = pEmit;
1373     }
1374     else
1375     {
1376         // Hardwire the metadata version to be the current runtime version so that the ngen image
1377         // does not change when the directory runtime is installed in different directory (e.g. v2.0.x86chk vs. v2.0.80826).
1378         BSTRHolder strVersion(SysAllocString(W("v")VER_PRODUCTVERSION_NO_QFE_STR_L));
1379         VARIANT versionOption;
1380         V_VT(&versionOption) = VT_BSTR;
1381         V_BSTR(&versionOption) = strVersion;
1382         IfFailThrow(m_zapper->m_pMetaDataDispenser->SetOption(MetaDataRuntimeVersion, &versionOption));
1383
1384         IfFailThrow(m_zapper->m_pMetaDataDispenser->
1385                     DefineScope(CLSID_CorMetaDataRuntime, 0, IID_IMetaDataAssemblyEmit,
1386                                 (IUnknown **) &m_pAssemblyEmit));
1387     }
1388
1389 #ifdef FEATURE_READYTORUN_COMPILER
1390     if (IsReadyToRunCompilation())
1391     {
1392         InitializeSectionsForReadyToRun();
1393     }
1394     else
1395 #endif
1396     {
1397         InitializeSections();
1398     }
1399
1400     // Set the module base address for the ngen native image
1401     CalculateZapBaseAddress();
1402 }
1403
1404
1405
1406
1407 //
1408 // Load the module and populate all the data-structures
1409 //
1410
1411 void ZapImage::Preload()
1412 {
1413
1414     CorProfileData *  pProfileData = NewProfileData();
1415     m_pPreloader = m_zapper->m_pEECompileInfo->PreloadModule(m_hModule, this, pProfileData);
1416 }
1417
1418 //
1419 // Store the module
1420 //
1421
1422 void ZapImage::LinkPreload()
1423 {
1424     m_pPreloader->Link();
1425 }
1426
1427 void ZapImage::OutputManifestMetadata()
1428 {
1429     //
1430     // Write out manifest metadata
1431     //
1432
1433     //
1434     // First, see if we have useful metadata to store
1435     //
1436
1437     BOOL fMetadata = FALSE;
1438
1439     if (m_pAssemblyEmit != NULL)
1440     {
1441         //
1442         // We may have added some assembly refs for exports.
1443         //
1444
1445         NonVMComHolder<IMetaDataAssemblyImport> pAssemblyImport;
1446         IfFailThrow(m_pAssemblyEmit->QueryInterface(IID_IMetaDataAssemblyImport,
1447                                                     (void **)&pAssemblyImport));
1448
1449         NonVMComHolder<IMetaDataImport> pImport;
1450         IfFailThrow(m_pAssemblyEmit->QueryInterface(IID_IMetaDataImport,
1451                                                     (void **)&pImport));
1452
1453         HCORENUM hEnum = 0;
1454         ULONG cRefs;
1455         IfFailThrow(pAssemblyImport->EnumAssemblyRefs(&hEnum, NULL, 0, &cRefs));
1456         IfFailThrow(pImport->CountEnum(hEnum, &cRefs));
1457         pImport->CloseEnum(hEnum);
1458
1459         if (cRefs > 0)
1460             fMetadata = TRUE;
1461
1462         //
1463         // If we are the main module, we have the assembly def for the zap file.
1464         //
1465
1466         mdAssembly a;
1467         if (pAssemblyImport->GetAssemblyFromScope(&a) == S_OK)
1468             fMetadata = TRUE;
1469     }
1470
1471     if (fMetadata)
1472     {
1473         // Metadata creates a new MVID for every instantiation.
1474         // However, we want the generated ngen image to always be the same
1475         // for the same input. So set the metadata MVID to NGEN_IMAGE_MVID.
1476
1477         NonVMComHolder<IMDInternalEmit> pMDInternalEmit;
1478         IfFailThrow(m_pAssemblyEmit->QueryInterface(IID_IMDInternalEmit,
1479                                                   (void**)&pMDInternalEmit));
1480
1481         IfFailThrow(pMDInternalEmit->ChangeMvid(NGEN_IMAGE_MVID));
1482
1483         m_pAssemblyMetaData = new (GetHeap()) ZapMetaData();
1484         m_pAssemblyMetaData->SetMetaData(m_pAssemblyEmit);
1485
1486         m_pMetaDataSection->Place(m_pAssemblyMetaData);
1487     }
1488 }
1489
1490 void ZapImage::OutputTables()
1491 {
1492     //
1493     // Copy over any resources to the native image
1494     //
1495
1496     COUNT_T size;
1497     PVOID resource = (PVOID)m_ModuleDecoder.GetResources(&size);
1498
1499     if (size != 0)
1500     {
1501         m_pResources = new (GetHeap()) ZapBlobPtr(resource, size);
1502         m_pResourcesSection->Place(m_pResources);
1503     }
1504
1505     CopyDebugDirEntry();
1506     CopyWin32Resources();
1507
1508     if (m_pILMetaData != NULL)
1509     {
1510         m_pILMetaData->CopyIL();
1511         m_pILMetaData->CopyMetaData();
1512     }
1513
1514     if (IsReadyToRunCompilation())
1515     {
1516         m_pILMetaData->CopyRVAFields();
1517     }
1518
1519     // Copy over the timestamp from IL image for determinism
1520     SetTimeDateStamp(m_ModuleDecoder.GetTimeDateStamp());
1521
1522     SetSubsystem(m_ModuleDecoder.GetSubsystem());
1523
1524     {
1525         USHORT dllCharacteristics = 0;
1526
1527 #ifndef _TARGET_64BIT_
1528         dllCharacteristics |= IMAGE_DLLCHARACTERISTICS_NO_SEH;
1529 #endif
1530
1531 #ifdef _TARGET_ARM_
1532         // Images without NX compat bit set fail to load on ARM
1533         dllCharacteristics |= IMAGE_DLLCHARACTERISTICS_NX_COMPAT;
1534 #endif
1535
1536         // Copy over selected DLL characteristics bits from IL image
1537         dllCharacteristics |= (m_ModuleDecoder.GetDllCharacteristics() & 
1538             (IMAGE_DLLCHARACTERISTICS_NX_COMPAT | IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE | IMAGE_DLLCHARACTERISTICS_APPCONTAINER));
1539
1540 #ifdef _DEBUG
1541         if (0 == CLRConfig::GetConfigValue(CLRConfig::INTERNAL_NoASLRForNgen))
1542 #endif // _DEBUG
1543         {
1544             dllCharacteristics |= IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE;
1545 #ifdef _TARGET_64BIT_
1546             // Large address aware, required for High Entry VA, is always enabled for 64bit native images.
1547             dllCharacteristics |= IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA;
1548 #endif
1549         }
1550
1551         SetDllCharacteristics(dllCharacteristics);
1552     }
1553
1554     if (IsReadyToRunCompilation())
1555     {
1556
1557         SetSizeOfStackReserve(m_ModuleDecoder.GetSizeOfStackReserve());
1558         SetSizeOfStackCommit(m_ModuleDecoder.GetSizeOfStackCommit());
1559     }
1560
1561 #if defined(FEATURE_PAL) && !defined(_TARGET_64BIT_)
1562     // To minimize wasted VA space on 32 bit systems align file to page bounaries (presumed to be 4K).
1563     SetFileAlignment(0x1000);
1564 #elif defined(_TARGET_ARM_) && defined(FEATURE_CORESYSTEM)
1565     if (!IsReadyToRunCompilation())
1566     {
1567         // On ARM CoreSys builds, crossgen will use 4k file alignment, as requested by Phone perf team
1568         // to improve perf on phones with compressed system partitions.
1569         SetFileAlignment(0x1000);
1570     }
1571 #endif
1572 }
1573
1574 ZapImage::CompileStatus ZapImage::CompileProfileDataWorker(mdToken token, unsigned methodProfilingDataFlags)
1575 {
1576     if ((TypeFromToken(token) != mdtMethodDef) ||
1577         (!m_pMDImport->IsValidToken(token)))
1578     {
1579         m_zapper->Info(W("Warning: Invalid method token %08x in profile data.\n"), token);
1580         return NOT_COMPILED;
1581     }
1582
1583 #ifdef _DEBUG
1584     static ConfigDWORD g_NgenOrder;
1585
1586     if ((g_NgenOrder.val(CLRConfig::INTERNAL_NgenOrder) & 2) == 2)
1587     {
1588         const ProfileDataHashEntry * foundEntry = profileDataHashTable.LookupPtr(token);
1589     
1590         if (foundEntry == NULL)
1591             return NOT_COMPILED;
1592
1593         // The md must match.
1594         _ASSERTE(foundEntry->md == token); 
1595         // The target position cannot be 0.
1596         _ASSERTE(foundEntry->pos > 0);
1597     }
1598 #endif
1599
1600     // Now compile the method
1601     return TryCompileMethodDef(token, methodProfilingDataFlags);
1602 }
1603
1604 //  ProfileDisableInlining
1605 //     Before we start compiling any methods we may need to suppress the inlining
1606 //     of certain methods based upon our profile data.
1607 //     This method will arrange to disable this inlining.
1608 //
1609 void ZapImage::ProfileDisableInlining()
1610 {
1611     // We suppress the inlining of any Hot methods that have the ExcludeHotMethodCode flag.
1612     // We want such methods to be Jitted at runtime rather than compiled in the AOT native image.
1613     // The inlining of such a method also need to be suppressed.
1614     //
1615     ProfileDataSection* methodProfileData = &(m_profileDataSections[MethodProfilingData]);
1616     if (methodProfileData->tableSize > 0)
1617     {
1618         for (DWORD i = 0; i < methodProfileData->tableSize; i++)
1619         {
1620             CORBBTPROF_TOKEN_INFO * pTokenInfo = &(methodProfileData->pTable[i]);
1621             unsigned methodProfilingDataFlags = pTokenInfo->flags;
1622
1623             // Hot methods can be marked to be excluded from the AOT native image.
1624             // We also need to disable inlining of such methods.
1625             //
1626             if ((methodProfilingDataFlags & (1 << DisableInlining)) != 0)
1627             {
1628                 // Disable the inlining of this method
1629                 //
1630                 // @ToDo: Figure out how to disable inlining for this method.               
1631             }
1632         }
1633     }
1634 }
1635
1636 //  CompileHotRegion
1637 //     Performs the compilation and placement for all methods in the the "Hot" code region
1638 //     Methods placed in this region typically correspond to all of the methods that were
1639 //     executed during any of the profiling scenarios.
1640 //
1641 void ZapImage::CompileHotRegion()
1642 {
1643     // Compile all of the methods that were executed during profiling into the "Hot" code region.
1644     //
1645     BeginRegion(CORINFO_REGION_HOT);
1646
1647     CorProfileData* pProfileData = GetProfileData();
1648         
1649     ProfileDataSection* methodProfileData = &(m_profileDataSections[MethodProfilingData]);
1650     if (methodProfileData->tableSize > 0)
1651     {
1652         // record the start of hot IBC methods.
1653         m_iIBCMethod = m_MethodCompilationOrder.GetCount();
1654
1655         //
1656         // Compile the hot methods in the order specified in the MethodProfilingData
1657         //
1658         for (DWORD i = 0; i < methodProfileData->tableSize; i++)
1659         {
1660             CompileStatus compileResult = NOT_COMPILED;
1661             CORBBTPROF_TOKEN_INFO * pTokenInfo = &(methodProfileData->pTable[i]);
1662
1663             mdToken token = pTokenInfo->token;
1664             unsigned methodProfilingDataFlags = pTokenInfo->flags;
1665             _ASSERTE(methodProfilingDataFlags != 0);
1666
1667             if (TypeFromToken(token) == mdtMethodDef)
1668             {
1669                 //
1670                 // Compile a non-generic method
1671                 // 
1672                 compileResult = CompileProfileDataWorker(token, methodProfilingDataFlags);
1673             }
1674             else if (TypeFromToken(token) == ibcMethodSpec)
1675             {
1676                 //
1677                 //  compile a generic/parameterized method
1678                 // 
1679                 CORBBTPROF_BLOB_PARAM_SIG_ENTRY *pBlobSigEntry = pProfileData->GetBlobSigEntry(token);
1680                 
1681                 if (pBlobSigEntry == NULL)
1682                 {
1683                     m_zapper->Info(W("Warning: Did not find definition for method token %08x in profile data.\n"), token);
1684                 }
1685                 else // (pBlobSigEntry  != NULL)
1686                 {
1687                     _ASSERTE(pBlobSigEntry->blob.token == token);
1688
1689                     // decode method desc
1690                     CORINFO_METHOD_HANDLE pMethod = m_pPreloader->FindMethodForProfileEntry(pBlobSigEntry);
1691                    
1692                     if (pMethod)
1693                     {
1694                         m_pPreloader->AddMethodToTransitiveClosureOfInstantiations(pMethod);
1695
1696                         compileResult = TryCompileInstantiatedMethod(pMethod, methodProfilingDataFlags);
1697                     }
1698                     else
1699                     {
1700                         // This generic/parameterized method is not part of the native image
1701                         // Either the IBC type  specified no longer exists or it is a SIMD types
1702                         // or the type can't be loaded in a ReadyToRun native image because of
1703                         // a cross-module type dependencies.
1704                         //
1705                         compileResult = COMPILE_EXCLUDED;
1706                     }
1707                 }
1708             }
1709
1710             // Update the 'flags' and 'compileResult' saved in the profileDataHashTable hash table.
1711             //
1712             hashBBUpdateFlagsAndCompileResult(token, methodProfilingDataFlags, compileResult);
1713         }
1714         // record the start of hot Generics methods.
1715         m_iGenericsMethod = m_MethodCompilationOrder.GetCount();
1716     }
1717
1718     // record the start of untrained code
1719     m_iUntrainedMethod = m_MethodCompilationOrder.GetCount();
1720
1721     EndRegion(CORINFO_REGION_HOT);
1722 }
1723
1724 //  CompileColdRegion
1725 //     Performs the compilation and placement for all methods in the the "Cold" code region
1726 //     Methods placed in this region typically correspond to all of the methods that were
1727 //     NOT executed during any of the profiling scenarios.
1728 //
1729 void ZapImage::CompileColdRegion()
1730 {
1731     // Compile all of the methods that were NOT executed during profiling into the "Cold" code region.
1732     //
1733
1734     BeginRegion(CORINFO_REGION_COLD);
1735     
1736     IMDInternalImport * pMDImport = m_pMDImport;
1737     
1738     HENUMInternalHolder hEnum(pMDImport);
1739     hEnum.EnumAllInit(mdtMethodDef);
1740     
1741     mdMethodDef md;
1742     while (pMDImport->EnumNext(&hEnum, &md))
1743     {
1744         //
1745         // Compile the remaining methods that weren't compiled during the CompileHotRegion phase
1746         //
1747         TryCompileMethodDef(md, 0);
1748     }
1749
1750     // Compile any generic code which lands in this LoaderModule
1751     // that resulted from the above compilations
1752     CORINFO_METHOD_HANDLE handle = m_pPreloader->NextUncompiledMethod();
1753     while (handle != NULL)
1754     {
1755         TryCompileInstantiatedMethod(handle, 0);
1756         handle = m_pPreloader->NextUncompiledMethod();
1757     }
1758     
1759     EndRegion(CORINFO_REGION_COLD);
1760 }
1761
1762 //  PlaceMethodIL
1763 //     Copy the IL for all method into the AOT native image
1764 //
1765 void ZapImage::PlaceMethodIL()
1766 {
1767     // Place the IL for all of the methods 
1768     //
1769     IMDInternalImport * pMDImport = m_pMDImport;
1770     HENUMInternalHolder hEnum(pMDImport);
1771     hEnum.EnumAllInit(mdtMethodDef);
1772     
1773     mdMethodDef md;
1774     while (pMDImport->EnumNext(&hEnum, &md))
1775     {
1776         if (m_pILMetaData != NULL)
1777         {
1778             // Copy IL for all methods. We treat errors during copying IL 
1779             // over as fatal error. These errors are typically caused by 
1780             // corrupted IL images.
1781             // 
1782             m_pILMetaData->EmitMethodIL(md);
1783         }
1784     }
1785 }
1786
1787 void ZapImage::Compile()
1788 {
1789     //
1790     // Compile all of the methods for our AOT native image
1791     //
1792
1793     bool doNothingNgen = false;
1794 #ifdef _DEBUG
1795     static ConfigDWORD fDoNothingNGen;
1796     doNothingNgen = !!fDoNothingNGen.val(CLRConfig::INTERNAL_ZapDoNothing);
1797 #endif
1798
1799     ProfileDisableInlining();
1800
1801     if (!doNothingNgen)
1802     {
1803         CompileHotRegion();
1804
1805         CompileColdRegion();
1806     }
1807
1808     PlaceMethodIL();
1809
1810     // Compute a preferred class layout order based on analyzing the graph
1811     // of which classes contain calls to other classes.
1812     ComputeClassLayoutOrder();
1813
1814     // Sort the unprofiled methods by this preferred class layout, if available
1815     if (m_fHasClassLayoutOrder)
1816     {
1817         SortUnprofiledMethodsByClassLayoutOrder();
1818     }
1819
1820     if (IsReadyToRunCompilation())
1821     {
1822         // Pretend that no methods are trained, so that everything is in single code section
1823         // READYTORUN: FUTURE: More than one code section
1824         m_iUntrainedMethod = 0;
1825     }
1826
1827     OutputCode(ProfiledHot);
1828     OutputCode(Unprofiled);
1829     OutputCode(ProfiledCold);
1830
1831     OutputCodeInfo(ProfiledHot);
1832     OutputCodeInfo(ProfiledCold);  // actually both Unprofiled and ProfiledCold
1833
1834     OutputGCInfo();
1835     OutputProfileData();
1836
1837 #ifdef FEATURE_READYTORUN_COMPILER
1838     if (IsReadyToRunCompilation())
1839     {
1840         OutputEntrypointsTableForReadyToRun();
1841         OutputDebugInfoForReadyToRun();
1842         OutputTypesTableForReadyToRun(m_pMDImport);
1843         OutputAttributePresenceFilter(m_pMDImport);
1844         OutputInliningTableForReadyToRun();
1845         OutputProfileDataForReadyToRun();
1846         if (IsLargeVersionBubbleEnabled())
1847         {
1848             OutputManifestMetadataForReadyToRun();
1849         }
1850     }
1851     else
1852 #endif
1853     {
1854         OutputDebugInfo();
1855     }
1856 }
1857
1858 struct CompileMethodStubContext
1859 {
1860     ZapImage *                  pImage;
1861     unsigned                    methodProfilingDataFlags;
1862     ZapImage::CompileStatus     enumCompileStubResult;
1863
1864     CompileMethodStubContext(ZapImage * _image, unsigned _methodProfilingDataFlags)
1865     {
1866         pImage                   = _image;
1867         methodProfilingDataFlags = _methodProfilingDataFlags;
1868         enumCompileStubResult    = ZapImage::NOT_COMPILED;
1869     }
1870 };
1871
1872 //-----------------------------------------------------------------------------
1873 // This method is a callback function use to compile any IL_STUBS that are
1874 // associated with a normal IL method.  It is called from CompileMethodStubIfNeeded
1875 // via the function pointer stored in the CompileMethodStubContext.
1876 // It handles the temporary change to the m_compilerFlags and removes any flags
1877 // that we don't want set when compiling IL_STUBS.
1878 //-----------------------------------------------------------------------------
1879
1880 // static void __stdcall 
1881 void ZapImage::TryCompileMethodStub(LPVOID pContext, CORINFO_METHOD_HANDLE hStub, CORJIT_FLAGS jitFlags)
1882 {
1883     STANDARD_VM_CONTRACT;
1884
1885     // The caller must always set the IL_STUB flag
1886     _ASSERTE(jitFlags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_IL_STUB));
1887
1888     CompileMethodStubContext *pCompileContext = reinterpret_cast<CompileMethodStubContext *>(pContext);
1889     ZapImage *pImage = pCompileContext->pImage;
1890
1891     CORJIT_FLAGS oldFlags = pImage->m_zapper->m_pOpt->m_compilerFlags;
1892
1893     CORJIT_FLAGS* pCompilerFlags = &pImage->m_zapper->m_pOpt->m_compilerFlags;
1894     pCompilerFlags->Add(jitFlags);
1895     pCompilerFlags->Clear(CORJIT_FLAGS::CORJIT_FLAG_PROF_ENTERLEAVE);
1896     pCompilerFlags->Clear(CORJIT_FLAGS::CORJIT_FLAG_DEBUG_CODE);
1897     pCompilerFlags->Clear(CORJIT_FLAGS::CORJIT_FLAG_DEBUG_EnC);
1898     pCompilerFlags->Clear(CORJIT_FLAGS::CORJIT_FLAG_DEBUG_INFO);
1899
1900     mdMethodDef md = mdMethodDefNil;
1901
1902     pCompileContext->enumCompileStubResult = pImage->TryCompileMethodWorker(hStub, md,
1903                                                          pCompileContext->methodProfilingDataFlags);
1904
1905     pImage->m_zapper->m_pOpt->m_compilerFlags = oldFlags;
1906 }
1907
1908 //-----------------------------------------------------------------------------
1909 // Helper for ZapImage::TryCompileMethodDef that indicates whether a given method def token refers to a
1910 // "vtable gap" method. These are pseudo-methods used to lay out the vtable for COM interop and as such don't
1911 // have any associated code (or even a method handle).
1912 //-----------------------------------------------------------------------------
1913 BOOL ZapImage::IsVTableGapMethod(mdMethodDef md)
1914 {
1915 #ifdef FEATURE_COMINTEROP 
1916     HRESULT hr;
1917     DWORD dwAttributes;
1918
1919     // Get method attributes and check that RTSpecialName was set for the method (this means the name has
1920     // semantic import to the runtime and must be formatted rigorously with one of a few well known rules).
1921     // Note that we just return false on any failure path since this will just lead to our caller continuing
1922     // to throw the exception they were about to anyway.
1923     hr = m_pMDImport->GetMethodDefProps(md, &dwAttributes);
1924     if (FAILED(hr) || !IsMdRTSpecialName(dwAttributes))
1925         return FALSE;
1926
1927     // Now check the name of the method. All vtable gap methods will have a prefix of "_VtblGap".
1928     LPCSTR szMethod;
1929     PCCOR_SIGNATURE pvSigBlob;
1930     ULONG cbSigBlob;    
1931     hr = m_pMDImport->GetNameAndSigOfMethodDef(md, &pvSigBlob, &cbSigBlob, &szMethod);
1932     if (FAILED(hr) || (strncmp(szMethod, "_VtblGap", 8) != 0))
1933         return FALSE;
1934
1935     // If we make it to here we have a vtable gap method.
1936     return TRUE;
1937 #else
1938     return FALSE;
1939 #endif // FEATURE_COMINTEROP
1940 }
1941
1942 //-----------------------------------------------------------------------------
1943 // This function is called for non-generic methods in the current assembly,
1944 // and for the typical "System.__Canon" instantiations of generic methods
1945 // in the current assembly.
1946 //-----------------------------------------------------------------------------
1947
1948 ZapImage::CompileStatus ZapImage::TryCompileMethodDef(mdMethodDef md, unsigned methodProfilingDataFlags)
1949 {
1950     _ASSERTE(!IsNilToken(md));
1951
1952     CORINFO_METHOD_HANDLE handle = NULL;
1953     CompileStatus         result = NOT_COMPILED;
1954
1955     if (ShouldCompileMethodDef(md))
1956     {
1957         handle = m_pPreloader->LookupMethodDef(md);
1958         if (handle == nullptr)
1959         {
1960             result = LOOKUP_FAILED;
1961         }
1962     }
1963     else
1964     {
1965         result = COMPILE_EXCLUDED;
1966     }
1967
1968     if (handle == NULL)
1969         return result;
1970
1971     // compile the method
1972     //
1973     CompileStatus methodCompileStatus = TryCompileMethodWorker(handle, md, methodProfilingDataFlags);
1974
1975     // Don't bother compiling the IL_STUBS if we failed to compile the parent IL method
1976     //
1977     if (methodCompileStatus == COMPILE_SUCCEED)
1978     {
1979         CompileMethodStubContext context(this, methodProfilingDataFlags);
1980
1981         // compile stubs associated with the method
1982         m_pPreloader->GenerateMethodStubs(handle, m_zapper->m_pOpt->m_ngenProfileImage,
1983                                           &TryCompileMethodStub,
1984                                           &context);
1985     }
1986
1987     return methodCompileStatus;
1988 }
1989
1990
1991 //-----------------------------------------------------------------------------
1992 // This function is called for non-"System.__Canon" instantiations of generic methods.
1993 // These could be methods defined in other assemblies too.
1994 //-----------------------------------------------------------------------------
1995
1996 ZapImage::CompileStatus ZapImage::TryCompileInstantiatedMethod(CORINFO_METHOD_HANDLE handle, 
1997                                                                unsigned methodProfilingDataFlags)
1998 {
1999     if (IsReadyToRunCompilation())
2000     {
2001         if (!GetCompileInfo()->IsInCurrentVersionBubble(m_zapper->m_pEEJitInfo->getMethodModule(handle)))
2002             return COMPILE_EXCLUDED;
2003     }
2004
2005     if (!ShouldCompileInstantiatedMethod(handle))
2006         return COMPILE_EXCLUDED;
2007
2008     // If we compiling this method because it was specified by the IBC profile data
2009     // then issue an warning if this method is not on our uncompiled method list
2010     // 
2011     if (methodProfilingDataFlags != 0)
2012     {
2013         if (methodProfilingDataFlags & (1 << ReadMethodCode))
2014         {
2015             // When we have stale IBC data the method could have been rejected from this image.
2016             if (!m_pPreloader->IsUncompiledMethod(handle))
2017             {
2018                 const char* szClsName;
2019                 const char* szMethodName = m_zapper->m_pEEJitInfo->getMethodName(handle, &szClsName);
2020
2021                 SString fullname(SString::Utf8, szClsName);
2022                 fullname.AppendUTF8(NAMESPACE_SEPARATOR_STR);
2023                 fullname.AppendUTF8(szMethodName);
2024
2025                 m_zapper->Info(W("Warning: Invalid method instantiation in profile data: %s\n"), fullname.GetUnicode());
2026
2027                 return NOT_COMPILED;
2028             }
2029         }
2030     }
2031    
2032     CompileStatus methodCompileStatus = TryCompileMethodWorker(handle, mdMethodDefNil, methodProfilingDataFlags);
2033
2034     // Don't bother compiling the IL_STUBS if we failed to compile the parent IL method
2035     //
2036     if (methodCompileStatus == COMPILE_SUCCEED)
2037     {
2038         CompileMethodStubContext context(this, methodProfilingDataFlags);
2039
2040         // compile stubs associated with the method
2041         m_pPreloader->GenerateMethodStubs(handle, m_zapper->m_pOpt->m_ngenProfileImage,
2042                                           &TryCompileMethodStub, 
2043                                           &context);
2044     }
2045
2046     return methodCompileStatus;
2047 }
2048
2049 //-----------------------------------------------------------------------------
2050
2051 ZapImage::CompileStatus ZapImage::TryCompileMethodWorker(CORINFO_METHOD_HANDLE handle, mdMethodDef md, 
2052                                                          unsigned methodProfilingDataFlags)
2053 {
2054     _ASSERTE(handle != NULL);
2055
2056     if (m_zapper->m_pOpt->m_onlyOneMethod && (m_zapper->m_pOpt->m_onlyOneMethod != md))
2057         return NOT_COMPILED;
2058
2059     if (GetCompileInfo()->HasCustomAttribute(handle, "System.Runtime.BypassNGenAttribute"))
2060         return NOT_COMPILED;
2061
2062 #ifdef FEATURE_READYTORUN_COMPILER
2063     // This is a quick workaround to opt specific methods out of ReadyToRun compilation to work around bugs.
2064     if (IsReadyToRunCompilation())
2065     {
2066         if (GetCompileInfo()->HasCustomAttribute(handle, "System.Runtime.BypassReadyToRunAttribute"))
2067             return NOT_COMPILED;
2068     }
2069 #endif
2070
2071     // Do we have a profile entry for this method?
2072     //
2073     if (methodProfilingDataFlags != 0)
2074     {
2075         // Report the profiling data flags for layout of the EE datastructures
2076         m_pPreloader->SetMethodProfilingFlags(handle, methodProfilingDataFlags);
2077
2078         // Hot methods can be marked to be excluded from the AOT native image.
2079         // A Jitted method executes faster than a ReadyToRun compiled method.
2080         //
2081         if ((methodProfilingDataFlags & (1 << ExcludeHotMethodCode)) != 0)
2082         {
2083             // returning COMPILE_HOT_EXCLUDED excludes this method from the AOT native image
2084             return COMPILE_HOT_EXCLUDED;
2085         }
2086
2087         // Cold methods can be marked to be excluded from the AOT native image.
2088         // We can reduced the size of the AOT native image by selectively
2089         // excluding the code for some of the cold methods.
2090         //
2091         if ((methodProfilingDataFlags & (1 << ExcludeColdMethodCode)) != 0)
2092         {
2093             // returning COMPILE_COLD_EXCLUDED excludes this method from the AOT native image
2094             return COMPILE_COLD_EXCLUDED;
2095         }
2096
2097         // If the code was never executed based on the profile data
2098         // then don't compile this method now. Wait until until later
2099         // when we are compiling the methods in the cold section.
2100         //
2101         if ((methodProfilingDataFlags & (1 << ReadMethodCode)) == 0)
2102         {
2103             // returning NOT_COMPILED will defer until later the compilation of this method
2104             return NOT_COMPILED;
2105         }
2106     }
2107     else  // we are compiling methods for the cold region
2108     {
2109         // Retrieve any information that we have about a previous compilation attempt of this method
2110         const ProfileDataHashEntry* pEntry = profileDataHashTable.LookupPtr(md);
2111         
2112         // When Partial Ngen is specified we will omit the AOT native code for every
2113         // method that does not have profile data
2114         //
2115         if (pEntry == nullptr && m_zapper->m_pOpt->m_fPartialNGen)
2116         {
2117             // returning COMPILE_COLD_EXCLUDED excludes this method from the AOT native image
2118             return COMPILE_COLD_EXCLUDED;
2119         }
2120
2121         if (pEntry != nullptr)
2122         { 
2123             if ((pEntry->status == COMPILE_HOT_EXCLUDED) || (pEntry->status == COMPILE_COLD_EXCLUDED))
2124             {
2125                 // returning COMPILE_HOT_EXCLUDED excludes this method from the AOT native image
2126                 return pEntry->status;
2127             }
2128         }
2129     }
2130
2131     // Have we already compiled it?
2132     if (GetCompiledMethod(handle) != NULL)
2133         return ALREADY_COMPILED;
2134
2135     _ASSERTE(m_zapper->m_pOpt->m_compilerFlags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_IL_STUB) || IsNilToken(md) || handle == m_pPreloader->LookupMethodDef(md));
2136
2137     CompileStatus result = NOT_COMPILED;
2138     
2139     CORINFO_MODULE_HANDLE module;
2140
2141     // We only compile IL_STUBs from the current assembly
2142     if (m_zapper->m_pOpt->m_compilerFlags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_IL_STUB))
2143         module = m_hModule;
2144     else
2145         module = m_zapper->m_pEEJitInfo->getMethodModule(handle);
2146
2147     ZapInfo zapInfo(this, md, handle, module, methodProfilingDataFlags);
2148
2149     EX_TRY
2150     {
2151         zapInfo.CompileMethod();
2152         result = COMPILE_SUCCEED;
2153     }
2154     EX_CATCH
2155     {
2156         // Continue unwinding if fatal error was hit.
2157         if (FAILED(g_hrFatalError))
2158             ThrowHR(g_hrFatalError);
2159
2160         Exception *ex = GET_EXCEPTION();
2161         HRESULT hrException = ex->GetHR();
2162
2163         CorZapLogLevel level;
2164
2165 #ifdef CROSSGEN_COMPILE
2166         // Warnings should not go to stderr during crossgen
2167         level = CORZAP_LOGLEVEL_WARNING;
2168 #else
2169         level = CORZAP_LOGLEVEL_ERROR;
2170
2171         m_zapper->m_failed = TRUE;
2172 #endif
2173
2174         result = COMPILE_FAILED;
2175
2176 #ifdef FEATURE_READYTORUN_COMPILER
2177         // NYI features in R2R - Stop crossgen from spitting unnecessary
2178         //     messages to the console
2179         if (IsReadyToRunCompilation())
2180         {
2181             // When compiling the method we may receive an exeception when the
2182             // method uses a feature that is Not Implemented for ReadyToRun 
2183             // or a Type Load exception if the method uses for a SIMD type.
2184             //
2185             // We skip the compilation of such methods and we don't want to
2186             // issue a warning or error
2187             //
2188             if ((hrException == E_NOTIMPL) || (hrException == (HRESULT)IDS_CLASSLOAD_GENERAL))
2189             {
2190                 result = NOT_COMPILED;
2191                 level = CORZAP_LOGLEVEL_INFO;
2192             }
2193         }
2194 #endif
2195         {
2196             StackSString message;
2197             ex->GetMessage(message);
2198
2199             // FileNotFound errors here can be converted into a single error string per ngen compile, 
2200             //  and the detailed error is available with verbose logging
2201             if (hrException == COR_E_FILENOTFOUND)
2202             {
2203                 StackSString logMessage(W("System.IO.FileNotFoundException: "));
2204                 logMessage.Append(message);
2205                 FileNotFoundError(logMessage.GetUnicode());
2206                 level = CORZAP_LOGLEVEL_INFO;
2207             }
2208
2209             m_zapper->Print(level, W("%s while compiling method %s\n"), message.GetUnicode(), zapInfo.m_currentMethodName.GetUnicode());
2210
2211             if ((result == COMPILE_FAILED) && (m_stats != NULL))
2212             {
2213                 if (!m_zapper->m_pOpt->m_compilerFlags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_IL_STUB))
2214                     m_stats->m_failedMethods++;
2215                 else
2216                     m_stats->m_failedILStubs++;
2217             }
2218         }
2219     }
2220     EX_END_CATCH(SwallowAllExceptions);
2221     
2222     return result;
2223 }
2224
2225
2226 // Should we compile this method, defined in the ngen'ing module?
2227 // Result is FALSE if any of the controls (only used by prejit.exe) exclude the method
2228 BOOL ZapImage::ShouldCompileMethodDef(mdMethodDef md)
2229 {
2230     DWORD partialNGenStressVal = PartialNGenStressPercentage();
2231     if (partialNGenStressVal &&
2232         // Module::AddCerListToRootTable has problems if mscorlib.dll is
2233         // a partial ngen image
2234         m_hModule != m_zapper->m_pEECompileInfo->GetLoaderModuleForMscorlib())
2235     {
2236         _ASSERTE(partialNGenStressVal <= 100);
2237         DWORD methodPercentageVal = (md % 100) + 1;
2238         if (methodPercentageVal <= partialNGenStressVal)
2239             return FALSE;
2240     }
2241     
2242     mdTypeDef td;
2243     IfFailThrow(m_pMDImport->GetParentToken(md, &td));
2244     
2245 #ifdef FEATURE_COMINTEROP
2246     mdToken tkExtends;
2247     if (td != mdTypeDefNil)
2248     {
2249         IfFailThrow(m_pMDImport->GetTypeDefProps(td, NULL, &tkExtends));
2250         
2251         mdAssembly tkAssembly;
2252         DWORD dwAssemblyFlags;
2253         
2254         IfFailThrow(m_pMDImport->GetAssemblyFromScope(&tkAssembly));
2255         if (TypeFromToken(tkAssembly) == mdtAssembly)
2256         {
2257             IfFailThrow(m_pMDImport->GetAssemblyProps(tkAssembly,
2258                                             NULL, NULL,     // Public Key
2259                                             NULL,           // Hash Algorithm
2260                                             NULL,           // Name
2261                                             NULL,           // MetaData
2262                                             &dwAssemblyFlags));
2263             
2264             if (IsAfContentType_WindowsRuntime(dwAssemblyFlags))
2265             {
2266                 if (TypeFromToken(tkExtends) == mdtTypeRef)
2267                 {
2268                     LPCSTR szNameSpace = NULL;
2269                     LPCSTR szName = NULL;
2270                     IfFailThrow(m_pMDImport->GetNameOfTypeRef(tkExtends, &szNameSpace, &szName));
2271                     
2272                     if (!strcmp(szNameSpace, "System") && !_stricmp((szName), "Attribute"))
2273                     {
2274                         return FALSE;
2275                     }
2276                 }
2277             }
2278         }
2279     }
2280 #endif
2281
2282 #ifdef _DEBUG
2283     static ConfigMethodSet fZapOnly;
2284     fZapOnly.ensureInit(CLRConfig::INTERNAL_ZapOnly);
2285
2286     static ConfigMethodSet fZapExclude;
2287     fZapExclude.ensureInit(CLRConfig::INTERNAL_ZapExclude);
2288
2289     PCCOR_SIGNATURE pvSigBlob;
2290     ULONG cbSigBlob;
2291
2292     // Get the name of the current method and its class
2293     LPCSTR szMethod;
2294     IfFailThrow(m_pMDImport->GetNameAndSigOfMethodDef(md, &pvSigBlob, &cbSigBlob, &szMethod));
2295     
2296     LPCWSTR wszClass = W("");
2297     SString sClass;
2298
2299     if (td != mdTypeDefNil)
2300     {
2301         LPCSTR szNameSpace = NULL;
2302         LPCSTR szName = NULL;
2303         
2304         IfFailThrow(m_pMDImport->GetNameOfTypeDef(td, &szName, &szNameSpace));
2305         
2306         const SString nameSpace(SString::Utf8, szNameSpace);
2307         const SString name(SString::Utf8, szName);
2308         sClass.MakeFullNamespacePath(nameSpace, name);
2309         wszClass = sClass.GetUnicode();
2310     }
2311
2312     MAKE_UTF8PTR_FROMWIDE(szClass,  wszClass);
2313
2314     if (!fZapOnly.isEmpty() && !fZapOnly.contains(szMethod, szClass, pvSigBlob))
2315     {
2316         LOG((LF_ZAP, LL_INFO1000, "Rejecting compilation of method %08x, %s::%s\n", md, szClass, szMethod));
2317         return FALSE;
2318     }
2319
2320     if (fZapExclude.contains(szMethod, szClass, pvSigBlob))
2321     {
2322         LOG((LF_ZAP, LL_INFO1000, "Rejecting compilation of method %08x, %s::%s\n", md, szClass, szMethod));
2323         return FALSE;
2324     }
2325
2326     LOG((LF_ZAP, LL_INFO1000, "Compiling method %08x, %s::%s\n", md, szClass, szMethod));
2327 #endif    
2328     
2329     return TRUE;
2330 }
2331
2332
2333 BOOL ZapImage::ShouldCompileInstantiatedMethod(CORINFO_METHOD_HANDLE handle)
2334 {
2335     DWORD partialNGenStressVal = PartialNGenStressPercentage();
2336     if (partialNGenStressVal &&
2337         // Module::AddCerListToRootTable has problems if mscorlib.dll is
2338         // a partial ngen image
2339         m_hModule != m_zapper->m_pEECompileInfo->GetLoaderModuleForMscorlib())
2340     {
2341         _ASSERTE(partialNGenStressVal <= 100);
2342         DWORD methodPercentageVal = (m_zapper->m_pEEJitInfo->getMethodHash(handle) % 100) + 1;
2343         if (methodPercentageVal <= partialNGenStressVal)
2344             return FALSE;
2345     }
2346
2347     return TRUE;
2348 }
2349
2350 HRESULT ZapImage::PrintTokenDescription(CorZapLogLevel level, mdToken token)
2351 {
2352     HRESULT hr;
2353
2354     if (RidFromToken(token) == 0)
2355         return S_OK;
2356
2357     LPCSTR szNameSpace = NULL;
2358     LPCSTR szName = NULL;
2359
2360     if (m_pMDImport->IsValidToken(token))
2361     {
2362         switch (TypeFromToken(token))
2363         {
2364             case mdtMemberRef:
2365             {
2366                 mdToken parent;
2367                 IfFailRet(m_pMDImport->GetParentOfMemberRef(token, &parent));
2368                 if (RidFromToken(parent) != 0)
2369                 {
2370                     PrintTokenDescription(level, parent);
2371                     m_zapper->Print(level, W("."));
2372                 }
2373                 IfFailRet(m_pMDImport->GetNameAndSigOfMemberRef(token, NULL, NULL, &szName));
2374                 break;
2375             }
2376
2377             case mdtMethodDef:
2378             {
2379                 mdToken parent;
2380                 IfFailRet(m_pMDImport->GetParentToken(token, &parent));
2381                 if (RidFromToken(parent) != 0)
2382                 {
2383                     PrintTokenDescription(level, parent);
2384                     m_zapper->Print(level, W("."));
2385                 }
2386                 IfFailRet(m_pMDImport->GetNameOfMethodDef(token, &szName));
2387                 break;
2388             }
2389
2390             case mdtTypeRef:
2391             {   
2392                 IfFailRet(m_pMDImport->GetNameOfTypeRef(token, &szNameSpace, &szName));
2393                 break;
2394             }
2395
2396             case mdtTypeDef:
2397             {
2398                 IfFailRet(m_pMDImport->GetNameOfTypeDef(token, &szName, &szNameSpace));
2399                 break;
2400             }
2401
2402             default:
2403                 break;
2404         }      
2405     }
2406     else
2407     {
2408         szName = "InvalidToken";
2409     }
2410
2411     SString fullName;
2412
2413     if (szNameSpace != NULL)
2414     {
2415         const SString nameSpace(SString::Utf8, szNameSpace);
2416         const SString name(SString::Utf8, szName);
2417         fullName.MakeFullNamespacePath(nameSpace, name);
2418     }
2419     else
2420     {
2421         fullName.SetUTF8(szName);
2422     }
2423
2424     m_zapper->Print(level, W("%s"), fullName.GetUnicode());
2425
2426     return S_OK;
2427 }
2428
2429
2430 HRESULT ZapImage::LocateProfileData()
2431 {
2432     if (m_zapper->m_pOpt->m_ignoreProfileData)
2433     {
2434         return S_FALSE;
2435     }
2436
2437     //
2438     // In the past, we have ignored profile data when instrumenting the assembly.
2439     // However, this creates significant differences between the tuning image and the eventual
2440     // optimized image (e.g. generic instantiations) which in turn leads to missed data during
2441     // training and cold touches during execution.  Instead, we take advantage of any IBC data
2442     // the assembly already has and attempt to make the tuning image as close as possible to
2443     // the final image.
2444     //
2445 #if 0
2446     if (m_zapper->m_pOpt->m_compilerFlags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_BBINSTR))
2447         return S_FALSE;
2448 #endif
2449
2450     //
2451     // Don't use IBC data from untrusted assemblies--this allows us to assume that
2452     // the IBC data is not malicious
2453     //
2454     if (m_zapper->m_pEEJitInfo->canSkipVerification(m_hModule) != CORINFO_VERIFICATION_CAN_SKIP)
2455     {
2456         return S_FALSE;
2457     }
2458
2459     //
2460     // See if there's profile data in the resource section of the PE
2461     //
2462     m_pRawProfileData = (BYTE*)m_ModuleDecoder.GetWin32Resource(W("PROFILE_DATA"), W("IBC"), &m_cRawProfileData);
2463
2464     if ((m_pRawProfileData != NULL) && (m_cRawProfileData != 0))
2465     {
2466         m_zapper->Info(W("Found embedded profile resource in %s.\n"), m_pModuleFileName);
2467         return S_OK;
2468     }
2469
2470     static ConfigDWORD g_UseIBCFile;
2471     if (g_UseIBCFile.val(CLRConfig::EXTERNAL_UseIBCFile) != 1)
2472         return S_OK;
2473
2474     //
2475     // Couldn't find profile resource--let's see if there's an ibc file to use instead
2476     //
2477
2478     SString path(m_pModuleFileName);
2479
2480     SString::Iterator dot = path.End();
2481     if (path.FindBack(dot, '.'))
2482     {
2483         SString slName(SString::Literal, "ibc");
2484         path.Replace(dot+1, path.End() - (dot+1), slName);
2485
2486         HandleHolder hFile = WszCreateFile(path.GetUnicode(),
2487                                      GENERIC_READ,
2488                                      FILE_SHARE_READ,
2489                                      NULL,
2490                                      OPEN_EXISTING,
2491                                      FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,
2492                                      NULL);
2493         if (hFile != INVALID_HANDLE_VALUE)
2494         {
2495             HandleHolder hMapFile = WszCreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
2496             DWORD dwFileLen = SafeGetFileSize(hFile, 0);
2497             if (dwFileLen != INVALID_FILE_SIZE)
2498             {
2499                 if (hMapFile == NULL)
2500                 {
2501                     m_zapper->Warning(W("Found profile data file %s, but could not open it"), path.GetUnicode());
2502                 }
2503                 else
2504                 {
2505                     m_zapper->Info(W("Found ibc file %s.\n"), path.GetUnicode());
2506
2507                     m_profileDataFile  = (BYTE*) MapViewOfFile(hMapFile, FILE_MAP_READ, 0, 0, 0);
2508
2509                     m_pRawProfileData  = m_profileDataFile;
2510                     m_cRawProfileData  = dwFileLen;
2511                 }
2512             }
2513         }
2514     }
2515
2516     return S_OK;
2517 }
2518
2519
2520 bool ZapImage::CanConvertIbcData()
2521 {
2522     static ConfigDWORD g_iConvertIbcData;
2523     DWORD val = g_iConvertIbcData.val(CLRConfig::UNSUPPORTED_ConvertIbcData);
2524     return (val != 0);
2525 }
2526
2527 HRESULT ZapImage::parseProfileData()
2528 {
2529     if (m_pRawProfileData == NULL)
2530     {
2531         return S_FALSE;
2532     }
2533
2534     ProfileReader profileReader(m_pRawProfileData, m_cRawProfileData);
2535
2536     CORBBTPROF_FILE_HEADER *fileHeader;
2537
2538     READ(fileHeader, CORBBTPROF_FILE_HEADER);
2539     if (fileHeader->HeaderSize < sizeof(CORBBTPROF_FILE_HEADER))
2540     {
2541         _ASSERTE(!"HeaderSize is too small");
2542         return E_FAIL;
2543     }
2544
2545     // Read any extra header data. It will be needed for V3 files.
2546
2547     DWORD extraHeaderDataSize = fileHeader->HeaderSize - sizeof(CORBBTPROF_FILE_HEADER);
2548     void *extraHeaderData = profileReader.Read(extraHeaderDataSize);
2549
2550     bool convertFromV1 = false;
2551     bool minified = false;
2552
2553     if (fileHeader->Magic != CORBBTPROF_MAGIC) 
2554     {
2555         _ASSERTE(!"ibcHeader contains bad values");
2556         return E_FAIL;
2557     }
2558
2559     // CoreCLR should never be presented with V1 IBC data.
2560     if (fileHeader->Version == CORBBTPROF_V3_VERSION)
2561     {
2562         CORBBTPROF_FILE_OPTIONAL_HEADER *optionalHeader =
2563             (CORBBTPROF_FILE_OPTIONAL_HEADER *)extraHeaderData;
2564
2565         if (!optionalHeader ||
2566             !CONTAINS_FIELD(optionalHeader, extraHeaderDataSize, Size) ||
2567             (optionalHeader->Size > extraHeaderDataSize))
2568         {
2569             m_zapper->Info(W("Optional header missing or corrupt."));
2570             return E_FAIL;
2571         }
2572
2573         if (CONTAINS_FIELD(optionalHeader, optionalHeader->Size, FileFlags))
2574         {
2575             minified = !!(optionalHeader->FileFlags & CORBBTPROF_FILE_FLAG_MINIFIED);
2576
2577             if (!m_zapper->m_pOpt->m_fPartialNGenSet)
2578             {
2579                 m_zapper->m_pOpt->m_fPartialNGen = !!(optionalHeader->FileFlags & CORBBTPROF_FILE_FLAG_PARTIAL_NGEN);
2580             }
2581         }
2582     }
2583     else if (fileHeader->Version != CORBBTPROF_V2_VERSION)
2584     {
2585         m_zapper->Info(W("Discarding profile data with unknown version."));
2586         return S_FALSE;
2587     }
2588
2589     // This module has profile data (this ends up controling the layout of physical and virtual
2590     // sections within the image, see ZapImage::AllocateVirtualSections.
2591     m_fHaveProfileData = true;
2592     m_zapper->m_pOpt->m_fHasAnyProfileData = true;
2593
2594     CORBBTPROF_SECTION_TABLE_HEADER *sectionHeader;
2595     READ(sectionHeader, CORBBTPROF_SECTION_TABLE_HEADER);
2596
2597     //
2598     // Parse the section table
2599     //
2600
2601     for (ULONG i = 0; i < sectionHeader->NumEntries; i++)
2602     {
2603         CORBBTPROF_SECTION_TABLE_ENTRY *entry;
2604         READ(entry,CORBBTPROF_SECTION_TABLE_ENTRY);
2605
2606         SectionFormat format = sectionHeader->Entries[i].FormatID;
2607         _ASSERTE(format >= 0);
2608         if (format < 0)
2609         {
2610             continue;
2611         }
2612
2613         if (convertFromV1)
2614         {
2615             if (format < LastTokenFlagSection)
2616             {
2617                 format = (SectionFormat) (format + 1);
2618             }
2619         }
2620
2621         _ASSERTE(format < SectionFormatCount);
2622
2623         if (format < SectionFormatCount)
2624         {
2625             BYTE *start = m_pRawProfileData + sectionHeader->Entries[i].Data.Offset;
2626             BYTE *end   = start             + sectionHeader->Entries[i].Data.Size;
2627
2628             if ((start > m_pRawProfileData)                     &&
2629                 (end   < m_pRawProfileData + m_cRawProfileData) &&
2630                 (start < end))
2631             {
2632                 _ASSERTE(m_profileDataSections[format].pData  == 0);
2633                 _ASSERTE(m_profileDataSections[format].dataSize == 0);
2634
2635                 m_profileDataSections[format].pData     = start;
2636                 m_profileDataSections[format].dataSize  = (DWORD) (end - start);
2637             }
2638             else
2639             {
2640                 _ASSERTE(!"Invalid profile section offset or size");
2641                 return E_FAIL;
2642             }
2643         }
2644     }
2645
2646     HRESULT hr = S_OK;
2647
2648     if (convertFromV1)
2649     {
2650         hr = convertProfileDataFromV1();
2651         if (FAILED(hr))
2652         {
2653             return hr;
2654         }
2655     }
2656     else if (minified)
2657     {
2658         hr = RehydrateProfileData();
2659         if (FAILED(hr))
2660         {
2661             return hr;
2662         }
2663     }
2664     else
2665     {
2666         //
2667         // For those sections that are collections of tokens, further parse that format to get
2668         // the token pointer and number of tokens
2669         //
2670
2671         for (int format = FirstTokenFlagSection; format < SectionFormatCount; format++)
2672         {
2673             if (m_profileDataSections[format].pData)
2674             {
2675                 SEEK(((ULONG) (m_profileDataSections[format].pData - m_pRawProfileData)));
2676
2677                 CORBBTPROF_TOKEN_LIST_SECTION_HEADER *header;
2678                 READ(header, CORBBTPROF_TOKEN_LIST_SECTION_HEADER);
2679
2680                 DWORD tableSize = header->NumTokens;
2681                 DWORD dataSize  = (m_profileDataSections[format].dataSize - sizeof(CORBBTPROF_TOKEN_LIST_SECTION_HEADER));
2682                 DWORD expectedSize = tableSize * sizeof (CORBBTPROF_TOKEN_INFO);
2683
2684                 if (dataSize == expectedSize)
2685                 {
2686                     BYTE * startOfTable = m_profileDataSections[format].pData + sizeof(CORBBTPROF_TOKEN_LIST_SECTION_HEADER);
2687                     m_profileDataSections[format].tableSize = tableSize;
2688                     m_profileDataSections[format].pTable = (CORBBTPROF_TOKEN_INFO *) startOfTable;
2689                 }
2690                 else
2691                 {
2692                     _ASSERTE(!"Invalid CORBBTPROF_TOKEN_LIST_SECTION_HEADER header");
2693                     return E_FAIL;
2694                 }
2695             }
2696         }
2697     }
2698
2699     ZapImage::ProfileDataSection * DataSection_ScenarioInfo = & m_profileDataSections[ScenarioInfo];
2700     if (DataSection_ScenarioInfo->pData != NULL)
2701     {
2702         CORBBTPROF_SCENARIO_INFO_SECTION_HEADER * header = (CORBBTPROF_SCENARIO_INFO_SECTION_HEADER *) DataSection_ScenarioInfo->pData;
2703         m_profileDataNumRuns = header->TotalNumRuns;
2704     }
2705
2706     return S_OK;
2707 }
2708
2709
2710 HRESULT ZapImage::convertProfileDataFromV1()
2711 {
2712     if (m_pRawProfileData == NULL)
2713     {
2714         return S_FALSE;
2715     }
2716
2717     //
2718     // For those sections that are collections of tokens, further parse that format to get
2719     // the token pointer and number of tokens
2720     //
2721
2722     ProfileReader profileReader(m_pRawProfileData, m_cRawProfileData);
2723
2724     for (SectionFormat format = FirstTokenFlagSection; format < SectionFormatCount; format = (SectionFormat) (format + 1))
2725     {
2726         if (m_profileDataSections[format].pData)
2727         {
2728             SEEK(((ULONG) (m_profileDataSections[format].pData - m_pRawProfileData)));
2729
2730             CORBBTPROF_TOKEN_LIST_SECTION_HEADER *header;
2731             READ(header, CORBBTPROF_TOKEN_LIST_SECTION_HEADER);
2732
2733             DWORD tableSize = header->NumTokens;
2734
2735             if (tableSize == 0)
2736             {
2737                 m_profileDataSections[format].tableSize = 0;
2738                 m_profileDataSections[format].pTable    = NULL;
2739                 continue;
2740             }
2741
2742             DWORD dataSize  = (m_profileDataSections[format].dataSize - sizeof(CORBBTPROF_TOKEN_LIST_SECTION_HEADER));
2743             DWORD expectedSize = tableSize * sizeof (CORBBTPROF_TOKEN_LIST_ENTRY_V1);
2744
2745             if (dataSize == expectedSize)
2746             {
2747                 DWORD  newDataSize  = tableSize * sizeof (CORBBTPROF_TOKEN_INFO);
2748
2749                 if (newDataSize < dataSize)
2750                     return E_FAIL;
2751
2752                 BYTE * startOfTable = new (GetHeap()) BYTE[newDataSize];
2753
2754                 CORBBTPROF_TOKEN_LIST_ENTRY_V1 * pOldEntry;
2755                 CORBBTPROF_TOKEN_INFO *    pNewEntry;
2756
2757                 pOldEntry = (CORBBTPROF_TOKEN_LIST_ENTRY_V1 *) (m_profileDataSections[format].pData + sizeof(CORBBTPROF_TOKEN_LIST_SECTION_HEADER));
2758                 pNewEntry = (CORBBTPROF_TOKEN_INFO *)    startOfTable;
2759
2760                 for (DWORD i=0; i<tableSize; i++)
2761                 {
2762                     pNewEntry->token = pOldEntry->token;
2763                     pNewEntry->flags = pOldEntry->flags;
2764                     pNewEntry->scenarios = 1;
2765
2766                     pOldEntry++;
2767                     pNewEntry++;
2768                 }
2769                 m_profileDataSections[format].tableSize = tableSize;
2770                 m_profileDataSections[format].pTable    = (CORBBTPROF_TOKEN_INFO *) startOfTable;
2771             }
2772             else
2773             {
2774                 _ASSERTE(!"Invalid CORBBTPROF_TOKEN_LIST_SECTION_HEADER header");
2775                 return E_FAIL;
2776             }
2777         }
2778     }
2779
2780     _ASSERTE(m_profileDataSections[ScenarioInfo].pData == 0);
2781     _ASSERTE(m_profileDataSections[ScenarioInfo].dataSize == 0);
2782
2783     //
2784     // Convert the MethodBlockCounts format from V1 to V2
2785     //
2786     CORBBTPROF_METHOD_BLOCK_COUNTS_SECTION_HEADER_V1 * mbcSectionHeader = NULL;
2787     if (m_profileDataSections[MethodBlockCounts].pData)
2788     {
2789         //
2790         // Compute the size of the method block count stream
2791         // 
2792         BYTE *  dstPtr           = NULL;
2793         BYTE *  srcPtr           = m_profileDataSections[MethodBlockCounts].pData;
2794         DWORD   maxSizeToRead    = m_profileDataSections[MethodBlockCounts].dataSize;
2795         DWORD   totalSizeNeeded  = 0; 
2796         DWORD   totalSizeRead    = 0;
2797        
2798         mbcSectionHeader = (CORBBTPROF_METHOD_BLOCK_COUNTS_SECTION_HEADER_V1 *) srcPtr;
2799
2800         totalSizeRead   += sizeof(CORBBTPROF_METHOD_BLOCK_COUNTS_SECTION_HEADER_V1);
2801         totalSizeNeeded += sizeof(CORBBTPROF_METHOD_BLOCK_COUNTS_SECTION_HEADER); 
2802         srcPtr          += sizeof(CORBBTPROF_METHOD_BLOCK_COUNTS_SECTION_HEADER_V1);
2803
2804         if (totalSizeRead > maxSizeToRead)
2805         {
2806             return E_FAIL;
2807         }
2808        
2809         for (DWORD i=0; (i < mbcSectionHeader->NumMethods); i++)
2810         {
2811             CORBBTPROF_METHOD_HEADER_V1* methodEntry = (CORBBTPROF_METHOD_HEADER_V1 *) srcPtr;
2812             DWORD sizeRead   = 0;
2813             DWORD sizeWrite  = 0;
2814
2815             sizeRead  += methodEntry->HeaderSize;
2816             sizeRead  += methodEntry->Size;
2817             sizeWrite += sizeof(CORBBTPROF_METHOD_HEADER);
2818             sizeWrite += methodEntry->Size;
2819
2820             totalSizeRead   += sizeRead;
2821             totalSizeNeeded += sizeWrite;            
2822
2823             if (totalSizeRead > maxSizeToRead)
2824             {
2825                 return E_FAIL;
2826             }
2827
2828             srcPtr += sizeRead;
2829         }
2830         assert(totalSizeRead == maxSizeToRead);
2831
2832         // Reset the srcPtr
2833         srcPtr = m_profileDataSections[MethodBlockCounts].pData;
2834        
2835         BYTE * newMethodData = new (GetHeap()) BYTE[totalSizeNeeded];
2836
2837         dstPtr = newMethodData;
2838
2839         memcpy(dstPtr, srcPtr, sizeof(CORBBTPROF_METHOD_BLOCK_COUNTS_SECTION_HEADER));
2840         srcPtr += sizeof(CORBBTPROF_METHOD_BLOCK_COUNTS_SECTION_HEADER_V1);
2841         dstPtr += sizeof(CORBBTPROF_METHOD_BLOCK_COUNTS_SECTION_HEADER);
2842         
2843         for (DWORD i=0; (i < mbcSectionHeader->NumMethods); i++)
2844         {
2845             CORBBTPROF_METHOD_HEADER_V1 *  methodEntryV1 = (CORBBTPROF_METHOD_HEADER_V1 *) srcPtr;
2846             CORBBTPROF_METHOD_HEADER *     methodEntry   = (CORBBTPROF_METHOD_HEADER *)    dstPtr;
2847             DWORD sizeRead   = 0;
2848             DWORD sizeWrite  = 0;
2849
2850             methodEntry->method.token   = methodEntryV1->MethodToken;
2851             methodEntry->method.ILSize  = 0;
2852             methodEntry->method.cBlock  = (methodEntryV1->Size / sizeof(CORBBTPROF_BLOCK_DATA));
2853             sizeRead  += methodEntryV1->HeaderSize; 
2854             sizeWrite += sizeof(CORBBTPROF_METHOD_HEADER);
2855
2856             memcpy( dstPtr + sizeof(CORBBTPROF_METHOD_HEADER),
2857                     srcPtr + sizeof(CORBBTPROF_METHOD_HEADER_V1), 
2858                     (methodEntry->method.cBlock * sizeof(CORBBTPROF_BLOCK_DATA)));
2859             sizeRead  += methodEntryV1->Size; 
2860             sizeWrite += (methodEntry->method.cBlock * sizeof(CORBBTPROF_BLOCK_DATA));
2861
2862             methodEntry->size    = sizeWrite;
2863             methodEntry->cDetail = 0;
2864             srcPtr += sizeRead;
2865             dstPtr += sizeWrite;
2866         }
2867        
2868         m_profileDataSections[MethodBlockCounts].pData    = newMethodData;
2869         m_profileDataSections[MethodBlockCounts].dataSize = totalSizeNeeded;
2870     }
2871
2872     //
2873     // Allocate the scenario info section
2874     //
2875     {
2876         DWORD   sizeNeeded  = sizeof(CORBBTPROF_SCENARIO_INFO_SECTION_HEADER) + sizeof(CORBBTPROF_SCENARIO_HEADER);
2877         BYTE *  newData     = new (GetHeap()) BYTE[sizeNeeded];
2878         BYTE *  dstPtr      = newData;
2879         {
2880             CORBBTPROF_SCENARIO_INFO_SECTION_HEADER *siHeader = (CORBBTPROF_SCENARIO_INFO_SECTION_HEADER *) dstPtr;
2881             
2882             if (mbcSectionHeader != NULL)
2883                 siHeader->TotalNumRuns = mbcSectionHeader->NumRuns;
2884             else
2885                 siHeader->TotalNumRuns = 1;
2886
2887             siHeader->NumScenarios = 1;
2888
2889             dstPtr += sizeof(CORBBTPROF_SCENARIO_INFO_SECTION_HEADER);
2890         }
2891         {
2892             CORBBTPROF_SCENARIO_HEADER *sHeader = (CORBBTPROF_SCENARIO_HEADER *) dstPtr;
2893
2894             sHeader->scenario.ordinal  = 1;
2895             sHeader->scenario.mask     = 1;
2896             sHeader->scenario.priority = 0;
2897             sHeader->scenario.numRuns  = 0;
2898             sHeader->scenario.cName    = 0; 
2899
2900             sHeader->size = sHeader->Size();
2901
2902             dstPtr += sizeof(CORBBTPROF_SCENARIO_HEADER);
2903         }
2904         m_profileDataSections[ScenarioInfo].pData = newData;
2905         m_profileDataSections[ScenarioInfo].dataSize = sizeNeeded;
2906     }
2907
2908     //
2909     // Convert the BlobStream format from V1 to V2 
2910     //   
2911     if (m_profileDataSections[BlobStream].dataSize > 0)
2912     {
2913         //
2914         // Compute the size of the blob stream
2915         // 
2916         
2917         BYTE *  srcPtr           = m_profileDataSections[BlobStream].pData;
2918         BYTE *  dstPtr           = NULL;
2919         DWORD   maxSizeToRead    = m_profileDataSections[BlobStream].dataSize;
2920         DWORD   totalSizeNeeded  = 0;
2921         DWORD   totalSizeRead    = 0;
2922         bool    done             = false;
2923         
2924         while (!done)
2925         {
2926             CORBBTPROF_BLOB_ENTRY_V1* blobEntry = (CORBBTPROF_BLOB_ENTRY_V1 *) srcPtr;
2927             DWORD sizeWrite  = 0;
2928             DWORD sizeRead   = 0;
2929
2930             if ((blobEntry->blobType >= MetadataStringPool) && (blobEntry->blobType <= MetadataUserStringPool))
2931             {
2932                 sizeWrite += sizeof(CORBBTPROF_BLOB_POOL_ENTRY);
2933                 sizeWrite += blobEntry->cBuffer;
2934                 sizeRead  += sizeof(CORBBTPROF_BLOB_ENTRY_V1);
2935                 sizeRead  += blobEntry->cBuffer;
2936             }
2937             else if ((blobEntry->blobType >= ParamTypeSpec) && (blobEntry->blobType <= ParamMethodSpec))
2938             {
2939                 sizeWrite += sizeof(CORBBTPROF_BLOB_PARAM_SIG_ENTRY);
2940                 sizeWrite += blobEntry->cBuffer;
2941                 if (blobEntry->blobType == ParamMethodSpec)
2942                 {
2943                     sizeWrite -= 1;  // Adjust for 
2944                 }
2945                 sizeRead  += sizeof(CORBBTPROF_BLOB_ENTRY_V1);
2946                 sizeRead  += blobEntry->cBuffer;
2947             }
2948             else if (blobEntry->blobType == EndOfBlobStream)
2949             {
2950                 sizeWrite += sizeof(CORBBTPROF_BLOB_ENTRY);
2951                 sizeRead  += sizeof(CORBBTPROF_BLOB_ENTRY_V1);
2952                 done = true;
2953             }
2954             else
2955             {
2956                 return E_FAIL;
2957             }
2958             
2959             totalSizeNeeded += sizeWrite;
2960             totalSizeRead   += sizeRead;
2961             
2962             if (sizeRead > maxSizeToRead)
2963             {
2964                 return E_FAIL;
2965             }
2966             
2967             srcPtr += sizeRead;
2968         }
2969
2970         assert(totalSizeRead == maxSizeToRead);
2971
2972         // Reset the srcPtr
2973         srcPtr = m_profileDataSections[BlobStream].pData;
2974         
2975         BYTE * newBlobData = new (GetHeap()) BYTE[totalSizeNeeded];
2976
2977         dstPtr = newBlobData;
2978         done = false;
2979         
2980         while (!done)
2981         {
2982             CORBBTPROF_BLOB_ENTRY_V1* blobEntryV1 = (CORBBTPROF_BLOB_ENTRY_V1 *) srcPtr;
2983             DWORD sizeWrite  = 0;
2984             DWORD sizeRead   = 0;
2985             
2986             if ((blobEntryV1->blobType >= MetadataStringPool) && (blobEntryV1->blobType <= MetadataUserStringPool))
2987             {
2988                 CORBBTPROF_BLOB_POOL_ENTRY* blobPoolEntry = (CORBBTPROF_BLOB_POOL_ENTRY*) dstPtr;
2989                 
2990                 blobPoolEntry->blob.type = blobEntryV1->blobType;
2991                 blobPoolEntry->blob.size = sizeof(CORBBTPROF_BLOB_POOL_ENTRY) + blobEntryV1->cBuffer;
2992                 blobPoolEntry->cBuffer   = blobEntryV1->cBuffer;
2993                 memcpy(blobPoolEntry->buffer, blobEntryV1->pBuffer, blobEntryV1->cBuffer);
2994                 
2995                 sizeWrite += sizeof(CORBBTPROF_BLOB_POOL_ENTRY);
2996                 sizeWrite += blobEntryV1->cBuffer;
2997                 sizeRead  += sizeof(CORBBTPROF_BLOB_ENTRY_V1);
2998                 sizeRead  += blobEntryV1->cBuffer;
2999             }
3000             else if ((blobEntryV1->blobType >= ParamTypeSpec) && (blobEntryV1->blobType <= ParamMethodSpec))
3001             {
3002                 CORBBTPROF_BLOB_PARAM_SIG_ENTRY* blobSigEntry = (CORBBTPROF_BLOB_PARAM_SIG_ENTRY*) dstPtr;
3003
3004                 blobSigEntry->blob.type  = blobEntryV1->blobType;
3005                 blobSigEntry->blob.size  = sizeof(CORBBTPROF_BLOB_PARAM_SIG_ENTRY) + blobEntryV1->cBuffer;
3006                 blobSigEntry->blob.token = 0;
3007                 blobSigEntry->cSig       = blobEntryV1->cBuffer; 
3008
3009                 if (blobEntryV1->blobType == ParamMethodSpec)
3010                 {
3011                     // Adjust cSig and blob.size
3012                     blobSigEntry->cSig--; 
3013                     blobSigEntry->blob.size--;
3014                 }
3015                 memcpy(blobSigEntry->sig, blobEntryV1->pBuffer, blobSigEntry->cSig);
3016                 
3017                 sizeWrite += sizeof(CORBBTPROF_BLOB_PARAM_SIG_ENTRY);
3018                 sizeWrite += blobSigEntry->cSig;
3019                 sizeRead  += sizeof(CORBBTPROF_BLOB_ENTRY_V1);
3020                 sizeRead  += blobEntryV1->cBuffer;
3021             }
3022             else if (blobEntryV1->blobType == EndOfBlobStream)
3023             {
3024                 CORBBTPROF_BLOB_ENTRY* blobEntry = (CORBBTPROF_BLOB_ENTRY*) dstPtr;
3025
3026                 blobEntry->type = blobEntryV1->blobType;
3027                 blobEntry->size = sizeof(CORBBTPROF_BLOB_ENTRY);
3028                 
3029                 sizeWrite += sizeof(CORBBTPROF_BLOB_ENTRY);
3030                 sizeRead  += sizeof(CORBBTPROF_BLOB_ENTRY_V1);
3031                 done = true;
3032             }
3033             else
3034             {
3035                 return E_FAIL;
3036             }
3037             srcPtr += sizeRead;
3038             dstPtr += sizeWrite;
3039         }
3040        
3041         m_profileDataSections[BlobStream].pData    = newBlobData;
3042         m_profileDataSections[BlobStream].dataSize = totalSizeNeeded;
3043     }
3044     else
3045     {
3046         m_profileDataSections[BlobStream].pData    = NULL;
3047         m_profileDataSections[BlobStream].dataSize = 0;
3048     }
3049
3050     return S_OK;
3051 }
3052
3053 void ZapImage::RehydrateBasicBlockSection()
3054 {
3055     ProfileDataSection &section = m_profileDataSections[MethodBlockCounts];
3056     if (!section.pData)
3057     {
3058         return;
3059     }
3060
3061     ProfileReader reader(section.pData, section.dataSize);
3062
3063     m_profileDataNumRuns = reader.Read<unsigned int>();
3064
3065     // The IBC data provides a hint to the number of basic blocks, which is
3066     // used here to determine how much space to allocate for the rehydrated
3067     // data.
3068     unsigned int blockCountHint = reader.Read<unsigned int>();
3069
3070     unsigned int numMethods = reader.Read<unsigned int>();
3071
3072     unsigned int expectedLength =
3073         sizeof(CORBBTPROF_METHOD_BLOCK_COUNTS_SECTION_HEADER) +
3074         sizeof(CORBBTPROF_METHOD_HEADER) * numMethods +
3075         sizeof(CORBBTPROF_BLOCK_DATA) * blockCountHint;
3076
3077     BinaryWriter writer(expectedLength, GetHeap());
3078
3079     writer.Write(numMethods);
3080
3081     mdToken lastMethodToken = 0x06000000;
3082
3083     CORBBTPROF_METHOD_HEADER methodHeader;
3084     methodHeader.cDetail = 0;
3085     methodHeader.method.ILSize = 0;
3086
3087     for (unsigned int i = 0; i < numMethods; ++i)
3088     {
3089         // Translate the method header
3090         unsigned int size = reader.Read7BitEncodedInt();
3091         unsigned int startPosition = reader.GetCurrentPos();
3092
3093         mdToken token = reader.ReadTokenWithMemory(lastMethodToken);
3094         unsigned int ilSize = reader.Read7BitEncodedInt();
3095         unsigned int firstBlockHitCount = reader.Read7BitEncodedInt();
3096
3097         unsigned int numOtherBlocks = reader.Read7BitEncodedInt();
3098
3099         methodHeader.method.cBlock = 1 + numOtherBlocks;
3100         methodHeader.method.token = token;
3101         methodHeader.method.ILSize = ilSize;
3102         methodHeader.size = (DWORD)methodHeader.Size();
3103
3104         writer.Write(methodHeader);
3105
3106         CORBBTPROF_BLOCK_DATA blockData;
3107
3108         // The first block is handled specially.
3109         blockData.ILOffset = 0;
3110         blockData.ExecutionCount = firstBlockHitCount;
3111
3112         writer.Write(blockData);
3113
3114         // Translate the rest of the basic blocks
3115         for (unsigned int j = 0; j < numOtherBlocks; ++j)
3116         {
3117             blockData.ILOffset = reader.Read7BitEncodedInt();
3118             blockData.ExecutionCount = reader.Read7BitEncodedInt();
3119
3120             writer.Write(blockData);
3121         }
3122
3123         if (!reader.Seek(startPosition + size))
3124         {
3125             ThrowHR(E_FAIL);
3126         }
3127     }
3128
3129     // If the expected and actual lengths differ, the result will still be
3130     // correct but performance may suffer slightly because of reallocations.
3131     _ASSERTE(writer.GetWrittenSize() == expectedLength);
3132
3133     section.pData = writer.GetBuffer();
3134     section.dataSize = writer.GetWrittenSize();
3135 }
3136
3137 void ZapImage::RehydrateTokenSection(int sectionFormat, unsigned int flagTable[255])
3138 {
3139     ProfileDataSection &section = m_profileDataSections[sectionFormat];
3140     ProfileReader reader(section.pData, section.dataSize);
3141
3142     unsigned int numTokens = reader.Read<unsigned int>();
3143
3144     unsigned int dataLength = sizeof(unsigned int) +
3145                               numTokens * sizeof(CORBBTPROF_TOKEN_INFO);
3146     BinaryWriter writer(dataLength, GetHeap());
3147
3148     writer.Write(numTokens);
3149
3150     mdToken lastToken = (sectionFormat - FirstTokenFlagSection) << 24;
3151
3152     CORBBTPROF_TOKEN_INFO tokenInfo;
3153     tokenInfo.scenarios = 1;
3154
3155     for (unsigned int i = 0; i < numTokens; ++i)
3156     {
3157         tokenInfo.token = reader.ReadTokenWithMemory(lastToken);
3158         tokenInfo.flags = reader.ReadFlagWithLookup(flagTable);
3159
3160         writer.Write(tokenInfo);
3161     }
3162
3163     _ASSERTE(writer.GetWrittenSize() == dataLength);
3164     
3165     section.pData = writer.GetBuffer();
3166     section.dataSize = writer.GetWrittenSize();
3167     section.pTable = (CORBBTPROF_TOKEN_INFO *)(section.pData + sizeof(unsigned int));
3168     section.tableSize = numTokens;
3169 }
3170
3171 void ZapImage::RehydrateBlobStream()
3172 {
3173     ProfileDataSection &section = m_profileDataSections[BlobStream];
3174
3175     ProfileReader reader(section.pData, section.dataSize);
3176
3177     // Evidence suggests that rehydrating the blob stream in Framework binaries
3178     // increases the size from 1.5-2x. When this was written, 1.85x minimized
3179     // the amount of extra memory allocated (about 48K in the worst case).
3180     BinaryWriter writer((DWORD)(section.dataSize * 1.85f), GetHeap());
3181
3182     mdToken LastBlobToken = 0;
3183     mdToken LastAssemblyToken = 0x23000000;
3184     mdToken LastExternalTypeToken = 0x62000000;
3185     mdToken LastExternalNamespaceToken = 0x61000000;
3186     mdToken LastExternalSignatureToken = 0x63000000;
3187
3188     int blobType = 0;
3189     do
3190     {
3191         // Read the blob header.
3192
3193         unsigned int sizeToRead = reader.Read7BitEncodedInt();
3194         unsigned int startPositionRead = reader.GetCurrentPos();
3195     
3196         blobType = reader.Read7BitEncodedInt();
3197         mdToken token = reader.ReadTokenWithMemory(LastBlobToken);
3198
3199         // Write out the blob header.
3200
3201         // Note the location in the write stream, and write a 0 there. Once
3202         // this blob has been written in its entirety, this location can be
3203         // used to calculate the real size and to go back to the right place
3204         // to write it.
3205
3206         unsigned int startPositionWrite = writer.GetWrittenSize();
3207         writer.Write(0U);
3208
3209         writer.Write(blobType);
3210         writer.Write(token);
3211
3212         // All blobs (except the end-of-stream indicator) end as:
3213         //     <data length> <data>
3214         // Two blob types (handled immediately below) include tokens as well.
3215         // Handle those first, then handle the common case.
3216
3217         if (blobType == ExternalTypeDef)
3218         {
3219             writer.Write(reader.ReadTokenWithMemory(LastAssemblyToken));
3220             writer.Write(reader.ReadTokenWithMemory(LastExternalTypeToken));
3221             writer.Write(reader.ReadTokenWithMemory(LastExternalNamespaceToken));
3222         }
3223         else if (blobType == ExternalMethodDef)
3224         {
3225             writer.Write(reader.ReadTokenWithMemory(LastExternalTypeToken));
3226             writer.Write(reader.ReadTokenWithMemory(LastExternalSignatureToken));
3227         }
3228
3229         if ((blobType >= MetadataStringPool) && (blobType < IllegalBlob))
3230         {
3231             // This blob is of known type and ends with data.
3232             unsigned int dataLength = reader.Read7BitEncodedInt();
3233             char *data = (char *)reader.Read(dataLength);
3234
3235             if (!data)
3236             {
3237                 ThrowHR(E_FAIL);
3238             }
3239
3240             writer.Write(dataLength);
3241             writer.Write(data, dataLength);
3242         }
3243
3244         // Write the size for this blob.
3245
3246         writer.WriteAt(startPositionWrite,
3247                        writer.GetWrittenSize() - startPositionWrite);
3248
3249         // Move to the next blob.
3250
3251         if (!reader.Seek(startPositionRead + sizeToRead))
3252         {
3253             ThrowHR(E_FAIL);
3254         }
3255     }
3256     while (blobType != EndOfBlobStream);
3257
3258     section.pData = writer.GetBuffer();
3259     section.dataSize = writer.GetWrittenSize();
3260 }
3261
3262 HRESULT ZapImage::RehydrateProfileData()
3263 {
3264     HRESULT hr = S_OK;
3265     unsigned int flagTable[255];
3266     memset(flagTable, 0xFF, sizeof(flagTable));
3267     
3268     EX_TRY
3269     {
3270         RehydrateBasicBlockSection();
3271         RehydrateBlobStream();
3272         for (int format = FirstTokenFlagSection;
3273              format < SectionFormatCount;
3274              ++format)
3275         {
3276             if (m_profileDataSections[format].pData)
3277             {
3278                 RehydrateTokenSection(format, flagTable);
3279             }
3280         }
3281     }
3282     EX_CATCH_HRESULT_NO_ERRORINFO(hr);
3283
3284     return hr;
3285 }
3286
3287 HRESULT ZapImage::hashMethodBlockCounts()
3288 {
3289     ProfileDataSection * DataSection_MethodBlockCounts = & m_profileDataSections[MethodBlockCounts];
3290
3291     if (!DataSection_MethodBlockCounts->pData)
3292     {
3293         return E_FAIL;
3294     }
3295
3296     ProfileReader profileReader(DataSection_MethodBlockCounts->pData, DataSection_MethodBlockCounts->dataSize);
3297
3298     CORBBTPROF_METHOD_BLOCK_COUNTS_SECTION_HEADER *mbcHeader;
3299     READ(mbcHeader,CORBBTPROF_METHOD_BLOCK_COUNTS_SECTION_HEADER);
3300
3301     for (DWORD i = 0; i < mbcHeader->NumMethods; i++)
3302     {
3303         ProfileDataHashEntry newEntry;
3304         newEntry.pos = profileReader.GetCurrentPos();
3305         
3306         CORBBTPROF_METHOD_HEADER *methodHeader;
3307         READ(methodHeader,CORBBTPROF_METHOD_HEADER);
3308         newEntry.md   = methodHeader->method.token;
3309         newEntry.size = methodHeader->size;
3310         newEntry.flags = 0;
3311         newEntry.status = NOT_COMPILED;
3312
3313         // Add the new entry to the table
3314         profileDataHashTable.Add(newEntry);
3315
3316         // Skip the profileData so we can read the next method.
3317         void *profileData;
3318         READ_SIZE(profileData, void, (methodHeader->size - sizeof(CORBBTPROF_METHOD_HEADER)));
3319     }
3320
3321     return S_OK;
3322 }
3323
3324 void ZapImage::hashBBUpdateFlagsAndCompileResult(mdToken token, unsigned methodProfilingDataFlags, ZapImage::CompileStatus compileResult)
3325 {
3326     // SHash only supports replacing an entry so we setup our newEntry and then perform a lookup
3327     //
3328     ProfileDataHashEntry newEntry;
3329     newEntry.md = token;
3330     newEntry.flags = methodProfilingDataFlags;
3331     newEntry.status = compileResult;
3332
3333     const ProfileDataHashEntry* pEntry = profileDataHashTable.LookupPtr(token);
3334     if (pEntry != nullptr)
3335     {
3336         assert(pEntry->md == newEntry.md);
3337         assert(pEntry->flags == 0);   // the flags should not be set at this point.
3338
3339         // Copy and keep the two fleids that were previously set
3340         newEntry.size = pEntry->size;
3341         newEntry.pos = pEntry->pos;
3342     }
3343     else // We have a method that doesn't have basic block counts
3344     {
3345         newEntry.size = 0;
3346         newEntry.pos = 0;
3347     }
3348     profileDataHashTable.AddOrReplace(newEntry);
3349 }
3350
3351 void ZapImage::LoadProfileData()
3352 {
3353     HRESULT hr = E_FAIL;
3354
3355     m_fHaveProfileData = false;
3356     m_pRawProfileData  = NULL;
3357     m_cRawProfileData  = 0;
3358
3359     EX_TRY
3360     {
3361         hr = LocateProfileData();
3362         
3363         if (hr == S_OK)
3364         {
3365             hr = parseProfileData();
3366             if (hr == S_OK)
3367             {
3368                 hr = hashMethodBlockCounts();
3369             }
3370         }
3371     }
3372     EX_CATCH
3373     {
3374         hr = E_FAIL;
3375     }
3376     EX_END_CATCH(SwallowAllExceptions);
3377     
3378     if (hr != S_OK)
3379     {
3380         m_fHaveProfileData = false;
3381         m_pRawProfileData = NULL;
3382         m_cRawProfileData = 0;
3383
3384         if (FAILED(hr))
3385         {
3386             m_zapper->Warning(W("Warning: Invalid profile data was ignored for %s\n"), m_pModuleFileName);
3387         }
3388     }
3389
3390 #ifdef CROSSGEN_COMPILE
3391     if (m_zapper->m_pOpt->m_fPartialNGen && (m_pRawProfileData == NULL || m_cRawProfileData == 0))
3392     {
3393         ThrowHR(CLR_E_CROSSGEN_NO_IBC_DATA_FOUND);
3394     }
3395 #endif
3396 }
3397
3398 // Initializes our form of the profile data stored in the assembly.
3399
3400 CorProfileData *  ZapImage::NewProfileData()
3401 {
3402     this->m_pCorProfileData = new CorProfileData(&m_profileDataSections[0]);
3403
3404     return this->m_pCorProfileData;
3405 }
3406
3407 // Returns the profile data stored in the assembly.
3408
3409 CorProfileData *  ZapImage::GetProfileData()
3410 {
3411     _ASSERTE(this->m_pCorProfileData != NULL);
3412
3413     return this->m_pCorProfileData;
3414 }
3415
3416 CorProfileData::CorProfileData(void *  rawProfileData)
3417 {
3418     ZapImage::ProfileDataSection * profileData =  (ZapImage::ProfileDataSection *) rawProfileData;
3419
3420     for (DWORD format = 0; format < SectionFormatCount; format++)
3421     {
3422         this->profilingTokenFlagsData[format].count = profileData[format].tableSize;
3423         this->profilingTokenFlagsData[format].data  = profileData[format].pTable;
3424     }
3425
3426     this->blobStream = (CORBBTPROF_BLOB_ENTRY *) profileData[BlobStream].pData;
3427 }
3428
3429
3430 // Determines whether a method can be called directly from another method (without
3431 // going through the prestub) in the current module.
3432 // callerFtn=NULL implies any/unspecified caller in the current module.
3433 //
3434 // Returns NULL if 'calleeFtn' cannot be called directly *at the current time*
3435 // Else returns the direct address that 'calleeFtn' can be called at.
3436
3437
3438 bool ZapImage::canIntraModuleDirectCall(
3439                         CORINFO_METHOD_HANDLE callerFtn,
3440                         CORINFO_METHOD_HANDLE targetFtn,
3441                         CorInfoIndirectCallReason *pReason,
3442                         CORINFO_ACCESS_FLAGS  accessFlags/*=CORINFO_ACCESS_ANY*/)
3443 {
3444     CorInfoIndirectCallReason reason;
3445     if (pReason == NULL)
3446         pReason = &reason;
3447     *pReason = CORINFO_INDIRECT_CALL_UNKNOWN;
3448
3449     // The caller should have checked that the method is in current loader module
3450     _ASSERTE(m_hModule == m_zapper->m_pEECompileInfo->GetLoaderModuleForEmbeddableMethod(targetFtn));
3451
3452     // No direct calls at all under some circumstances
3453
3454     if (m_zapper->m_pOpt->m_compilerFlags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_PROF_ENTERLEAVE)
3455         && !m_pPreloader->IsDynamicMethod(callerFtn))
3456     {
3457         *pReason = CORINFO_INDIRECT_CALL_PROFILING;
3458         goto CALL_VIA_ENTRY_POINT;
3459     }
3460
3461     // Does the methods's class have a cctor, etc?
3462
3463     if (!m_pPreloader->CanSkipMethodPreparation(callerFtn, targetFtn, pReason, accessFlags))
3464         goto CALL_VIA_ENTRY_POINT;
3465
3466     ZapMethodHeader * pMethod;
3467     pMethod = GetCompiledMethod(targetFtn);
3468
3469     // If we have not compiled the method then we can't call direct
3470
3471     if (pMethod == NULL)
3472     {
3473         *pReason = CORINFO_INDIRECT_CALL_NO_CODE;
3474         goto CALL_VIA_ENTRY_POINT;
3475     }
3476
3477     // Does the method have fixups?
3478
3479     if (pMethod->HasFixups() != NULL)
3480     {
3481         *pReason = CORINFO_INDIRECT_CALL_FIXUPS;
3482         goto CALL_VIA_ENTRY_POINT;
3483     }
3484
3485 #ifdef _DEBUG
3486     const char* clsName, * methodName;
3487     methodName = m_zapper->m_pEEJitInfo->getMethodName(targetFtn, &clsName);
3488     LOG((LF_ZAP, LL_INFO10000, "getIntraModuleDirectCallAddr: Success %s::%s\n",
3489         clsName, methodName));
3490 #endif
3491
3492     return true;
3493
3494 CALL_VIA_ENTRY_POINT:
3495
3496 #ifdef _DEBUG
3497     methodName = m_zapper->m_pEEJitInfo->getMethodName(targetFtn, &clsName);
3498     LOG((LF_ZAP, LL_INFO10000, "getIntraModuleDirectCallAddr: Via EntryPoint %s::%s\n",
3499          clsName, methodName));
3500 #endif
3501
3502     return false;
3503 }
3504
3505 //
3506 // Relocations
3507 //
3508
3509 void ZapImage::WriteReloc(PVOID pSrc, int offset, ZapNode * pTarget, int targetOffset, ZapRelocationType type)
3510 {
3511     _ASSERTE(!IsWritingRelocs());
3512
3513     _ASSERTE(m_pBaseRelocs != NULL);
3514     m_pBaseRelocs->WriteReloc(pSrc, offset, pTarget, targetOffset, type);
3515 }
3516
3517 ZapImage * ZapImage::GetZapImage()
3518 {
3519     return this;
3520 }
3521
3522 void ZapImage::FileNotFoundError(LPCWSTR pszMessage)
3523 {
3524     SString message(pszMessage);
3525
3526     for (COUNT_T i = 0; i < fileNotFoundErrorsTable.GetCount(); i++)
3527     {
3528         // Check to see if same error has already been displayed for this ngen operation
3529         if (message.Equals(fileNotFoundErrorsTable[i]))
3530             return;
3531     }
3532
3533     CorZapLogLevel level;
3534
3535 #ifdef CROSSGEN_COMPILE
3536     // Warnings should not go to stderr during crossgen
3537     level = CORZAP_LOGLEVEL_WARNING;
3538 #else
3539     level = CORZAP_LOGLEVEL_ERROR;
3540 #endif
3541
3542     m_zapper->Print(level, W("Warning: %s.\n"), pszMessage);
3543
3544     fileNotFoundErrorsTable.Append(message);
3545 }
3546
3547 void ZapImage::Error(mdToken token, HRESULT hr, UINT resID,  LPCWSTR message)
3548 {
3549     // Missing dependencies are reported as fatal errors in code:CompilationDomain::BindAssemblySpec.
3550     // Avoid printing redundant error message for them.
3551     if (FAILED(g_hrFatalError))
3552         ThrowHR(g_hrFatalError);
3553
3554     // COM introduces the notion of a vtable gap method, which is not a real method at all but instead
3555     // aids in the explicit layout of COM interop vtables. These methods have no implementation and no
3556     // direct runtime state tracking them. Trying to lookup a method handle for a vtable gap method will
3557     // throw an exception but we choose to let that happen and filter out the warning here in the
3558     // handler because (a) vtable gap methods are rare and (b) it's not all that cheap to identify them
3559     // beforehand.
3560     if ((TypeFromToken(token) == mdtMethodDef) && IsVTableGapMethod(token))
3561     {
3562         return;
3563     }
3564
3565     CorZapLogLevel level = CORZAP_LOGLEVEL_ERROR;
3566
3567     // Some warnings are demoted to informational level
3568     if (resID == IDS_EE_SIMD_NGEN_DISALLOWED)
3569     {
3570         // Supress printing of "Target-dependent SIMD vector types may not be used with ngen."
3571         level = CORZAP_LOGLEVEL_INFO;
3572     }
3573
3574     if (resID == IDS_EE_HWINTRINSIC_NGEN_DISALLOWED)
3575     {
3576         // Supress printing of "Hardware intrinsics may not be used with ngen."
3577         level = CORZAP_LOGLEVEL_INFO;
3578     }
3579
3580 #ifdef CROSSGEN_COMPILE
3581     if ((resID == IDS_IBC_MISSING_EXTERNAL_TYPE) ||
3582         (resID == IDS_IBC_MISSING_EXTERNAL_METHOD))
3583     {
3584         // Suppress printing IBC related warnings except in verbose mode.
3585         if (m_zapper->m_pOpt->m_ignoreErrors && !m_zapper->m_pOpt->m_verbose)
3586             return;
3587
3588         // Supress printing of "The generic type/method specified by the IBC data is not available to this assembly"
3589         level = CORZAP_LOGLEVEL_INFO;
3590     }   
3591 #endif        
3592
3593     if (m_zapper->m_pOpt->m_ignoreErrors)
3594     {
3595 #ifdef CROSSGEN_COMPILE
3596         // Warnings should not go to stderr during crossgen
3597         if (level == CORZAP_LOGLEVEL_ERROR)
3598         {
3599             level = CORZAP_LOGLEVEL_WARNING;
3600         }
3601 #endif
3602         m_zapper->Print(level, W("Warning: "));
3603     }
3604     else
3605     {
3606         m_zapper->Print(level, W("Error: "));
3607     }
3608
3609     if (message != NULL)
3610         m_zapper->Print(level, W("%s"), message);
3611     else
3612         m_zapper->PrintErrorMessage(level, hr);
3613
3614     m_zapper->Print(level, W(" while resolving 0x%x - "), token);
3615     PrintTokenDescription(level, token);
3616     m_zapper->Print(level, W(".\n"));
3617
3618     if (m_zapper->m_pOpt->m_ignoreErrors)
3619         return;
3620
3621     IfFailThrow(hr);
3622 }
3623
3624 ZapNode * ZapImage::GetInnerPtr(ZapNode * pNode, SSIZE_T offset)
3625 {
3626     return m_pInnerPtrs->Get(pNode, offset);
3627 }
3628
3629 ZapNode * ZapImage::GetHelperThunk(CorInfoHelpFunc ftnNum)
3630 {
3631     ZapNode * pHelperThunk = m_pHelperThunks[ftnNum];
3632
3633     if (pHelperThunk == NULL)
3634     {
3635         pHelperThunk = new (GetHeap()) ZapHelperThunk(ftnNum);
3636 #ifdef _TARGET_ARM_
3637         pHelperThunk = GetInnerPtr(pHelperThunk, THUMB_CODE);
3638 #endif
3639         m_pHelperThunks[ftnNum] = pHelperThunk;
3640     }
3641
3642     // Ensure that the thunk is placed
3643     ZapNode * pTarget = pHelperThunk;
3644     if (pTarget->GetType() == ZapNodeType_InnerPtr)
3645         pTarget = ((ZapInnerPtr *)pTarget)->GetBase();
3646     if (!pTarget->IsPlaced())
3647         m_pHelperTableSection->Place(pTarget);
3648
3649     return pHelperThunk;
3650 }
3651
3652 //
3653 // Compute a class-layout order based on a breadth-first traversal of 
3654 // the class graph (based on what classes contain calls to other classes).
3655 // We cannot afford time or space to build the graph, so we do processing
3656 // in place.
3657 // 
3658 void ZapImage::ComputeClassLayoutOrder()
3659 {
3660     // In order to make the computation efficient, we need to store per-class 
3661     // intermediate values in the class layout field.  These come in two forms:
3662     // 
3663     //   - An entry with the UNSEEN_CLASS_FLAG set is one that is yet to be encountered.
3664     //   - An entry with METHOD_INDEX_FLAG set is an index into the m_MethodCompilationOrder list
3665     //     indicating where the unprofiled methods of this class begin
3666     //   
3667     // Both flags begin set (by InitializeClassLayoutOrder) since the value initialized is
3668     // the method index and the class has not been encountered by the algorithm.
3669     // When a class layout has been computed, both of these flags will have been stripped.
3670
3671
3672     // Early-out in the (probably impossible) case that these bits weren't available
3673     if (m_MethodCompilationOrder.GetCount() >= UNSEEN_CLASS_FLAG ||
3674         m_MethodCompilationOrder.GetCount() >= METHOD_INDEX_FLAG)
3675     {
3676         return;
3677     }
3678
3679     // Allocate the queue for the breadth-first traversal.
3680     // Note that the use of UNSEEN_CLASS_FLAG ensures that no class is enqueued more
3681     // than once, so we can use that bound for the size of the queue.
3682     CORINFO_CLASS_HANDLE * classQueue = new CORINFO_CLASS_HANDLE[m_ClassLayoutOrder.GetCount()];
3683
3684     unsigned classOrder = 0;
3685     for (COUNT_T i = m_iUntrainedMethod; i < m_MethodCompilationOrder.GetCount(); i++)
3686     {
3687         unsigned classQueueNext = 0;
3688         unsigned classQueueEnd = 0;
3689         COUNT_T  methodIndex = 0;
3690
3691         //
3692         // Find an unprocessed method to seed the next breadth-first traversal.
3693         //
3694
3695         ZapMethodHeader * pMethod = m_MethodCompilationOrder[i];
3696         const ClassLayoutOrderEntry * pEntry = m_ClassLayoutOrder.LookupPtr(pMethod->m_classHandle);
3697         _ASSERTE(pEntry);
3698         
3699         if ((pEntry->m_order & UNSEEN_CLASS_FLAG) == 0)
3700         {
3701             continue;
3702         }
3703
3704         //
3705         // Enqueue the method's class and start the traversal.
3706         //
3707
3708         classQueue[classQueueEnd++] = pMethod->m_classHandle;
3709         ((ClassLayoutOrderEntry *)pEntry)->m_order &= ~UNSEEN_CLASS_FLAG;
3710
3711         while (classQueueNext < classQueueEnd)
3712         {
3713             //
3714             // Dequeue a class and pull out the index of its first method
3715             //
3716             
3717             CORINFO_CLASS_HANDLE dequeuedClassHandle = classQueue[classQueueNext++];
3718             _ASSERTE(dequeuedClassHandle != NULL);
3719
3720             pEntry = m_ClassLayoutOrder.LookupPtr(dequeuedClassHandle);
3721             _ASSERTE(pEntry);
3722             _ASSERTE((pEntry->m_order & UNSEEN_CLASS_FLAG) == 0);
3723             _ASSERTE((pEntry->m_order & METHOD_INDEX_FLAG) != 0);
3724
3725             methodIndex = pEntry->m_order & ~METHOD_INDEX_FLAG;
3726             _ASSERTE(methodIndex < m_MethodCompilationOrder.GetCount());
3727
3728             //
3729             // Set the real layout order of the class, and examine its unprofiled methods
3730             //
3731             
3732             ((ClassLayoutOrderEntry *)pEntry)->m_order = ++classOrder;
3733                 
3734             pMethod = m_MethodCompilationOrder[methodIndex];
3735             _ASSERTE(pMethod->m_classHandle == dequeuedClassHandle);
3736
3737             while (pMethod->m_classHandle == dequeuedClassHandle)
3738             {
3739
3740                 //
3741                 // For each unprofiled method, find target classes and enqueue any that haven't been seen
3742                 //
3743
3744                 ZapMethodHeader::PartialTargetMethodIterator it(pMethod);
3745
3746                 CORINFO_METHOD_HANDLE targetMethodHandle;
3747                 while (it.GetNext(&targetMethodHandle))
3748                 {
3749                     CORINFO_CLASS_HANDLE targetClassHandle = GetJitInfo()->getMethodClass(targetMethodHandle);
3750                     if (targetClassHandle != pMethod->m_classHandle)
3751                     {
3752                         pEntry = m_ClassLayoutOrder.LookupPtr(targetClassHandle);
3753
3754                         if (pEntry && (pEntry->m_order & UNSEEN_CLASS_FLAG) != 0)
3755                         {
3756                             _ASSERTE(classQueueEnd < m_ClassLayoutOrder.GetCount());
3757                             classQueue[classQueueEnd++] = targetClassHandle;
3758
3759                             ((ClassLayoutOrderEntry *)pEntry)->m_order &= ~UNSEEN_CLASS_FLAG;
3760                         }
3761                     }
3762                 }
3763
3764                 if (++methodIndex == m_MethodCompilationOrder.GetCount())
3765                 {
3766                     break;
3767                 }
3768                     
3769                 pMethod = m_MethodCompilationOrder[methodIndex];
3770             }
3771         }
3772     }
3773
3774     for (COUNT_T i = m_iUntrainedMethod; i < m_MethodCompilationOrder.GetCount(); i++)
3775     {
3776         ZapMethodHeader * pMethod = m_MethodCompilationOrder[i];
3777         pMethod->m_cachedLayoutOrder = LookupClassLayoutOrder(pMethod->m_classHandle);
3778     }
3779
3780     m_fHasClassLayoutOrder = true;
3781
3782     delete [] classQueue;
3783 }
3784
3785 static int __cdecl LayoutOrderCmp(const void* a_, const void* b_)
3786 {
3787     ZapMethodHeader * a = *((ZapMethodHeader**)a_);
3788     ZapMethodHeader * b = *((ZapMethodHeader**)b_);
3789
3790     int layoutDiff = a->GetCachedLayoutOrder() - b->GetCachedLayoutOrder();
3791     if (layoutDiff != 0)
3792         return layoutDiff;
3793
3794     // Use compilation order as secondary key to get predictable ordering within the bucket
3795     return a->GetCompilationOrder() - b->GetCompilationOrder();
3796 }
3797
3798 void ZapImage::SortUnprofiledMethodsByClassLayoutOrder()
3799 {
3800     qsort(&m_MethodCompilationOrder[m_iUntrainedMethod], m_MethodCompilationOrder.GetCount() - m_iUntrainedMethod, sizeof(ZapMethodHeader *), LayoutOrderCmp);
3801 }