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.
9 // NGEN-specific infrastructure for writing PE files.
11 // ======================================================================================
16 #include "zaprelocs.h"
18 #include "zapinnerptr.h"
19 #include "zapwrapper.h"
21 #include "zapheaders.h"
22 #include "zapmetadata.h"
24 #include "zapimport.h"
26 #ifdef FEATURE_READYTORUN_COMPILER
27 #include "zapreadytorun.h"
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)) )
36 /* --------------------------------------------------------------------------- *
37 * Destructor wrapper objects
38 * --------------------------------------------------------------------------- */
40 ZapImage::ZapImage(Zapper *zapper)
42 m_stats(new ZapperStats())
43 /* Everything else is initialized to 0 by default */
49 #ifdef ZAP_HASHTABLE_TUNING
50 // If ZAP_HASHTABLE_TUNING is defined, preallocate is overloaded to print the tunning constants
60 if (m_pModuleFileName != NULL)
61 delete [] m_pModuleFileName;
63 if (m_pMDImport != NULL)
64 m_pMDImport->Release();
66 if (m_pAssemblyEmit != NULL)
67 m_pAssemblyEmit->Release();
69 if (m_profileDataFile != NULL)
70 UnmapViewOfFile(m_profileDataFile);
73 m_pPreloader->Release();
75 if (m_pImportSectionsTable != NULL)
76 m_pImportSectionsTable->~ZapImportSectionsTable();
78 if (m_pGCInfoTable != NULL)
79 m_pGCInfoTable->~ZapGCInfoTable();
81 #ifdef WIN64EXCEPTIONS
82 if (m_pUnwindDataTable != NULL)
83 m_pUnwindDataTable->~ZapUnwindDataTable();
86 if (m_pStubDispatchDataTable != NULL)
87 m_pStubDispatchDataTable->~ZapImportSectionSignatures();
89 if (m_pExternalMethodDataTable != NULL)
90 m_pExternalMethodDataTable->~ZapImportSectionSignatures();
92 if (m_pDynamicHelperDataTable != NULL)
93 m_pDynamicHelperDataTable->~ZapImportSectionSignatures();
95 if (m_pDebugInfoTable != NULL)
96 m_pDebugInfoTable->~ZapDebugInfoTable();
98 if (m_pVirtualSectionsTable != NULL)
99 m_pVirtualSectionsTable->~ZapVirtualSectionsTable();
101 if (m_pILMetaData != NULL)
102 m_pILMetaData->~ZapILMetaData();
104 if (m_pBaseRelocs != NULL)
105 m_pBaseRelocs->~ZapBaseRelocs();
107 if (m_pAssemblyMetaData != NULL)
108 m_pAssemblyMetaData->~ZapMetaData();
111 // Destruction of auxiliary tables in alphabetical order
114 if (m_pImportTable != NULL)
115 m_pImportTable->~ZapImportTable();
117 if (m_pInnerPtrs != NULL)
118 m_pInnerPtrs->~ZapInnerPtrTable();
120 if (m_pMethodEntryPoints != NULL)
121 m_pMethodEntryPoints->~ZapMethodEntryPointTable();
123 if (m_pWrappers != NULL)
124 m_pWrappers->~ZapWrapperTable();
127 void ZapImage::InitializeSections()
129 AllocateVirtualSections();
131 m_pCorHeader = new (GetHeap()) ZapCorHeader(this);
132 m_pHeaderSection->Place(m_pCorHeader);
134 SetDirectoryEntry(IMAGE_DIRECTORY_ENTRY_COMHEADER, m_pCorHeader);
136 m_pNativeHeader = new (GetHeap()) ZapNativeHeader(this);
137 m_pHeaderSection->Place(m_pNativeHeader);
139 m_pCodeManagerEntry = new (GetHeap()) ZapCodeManagerEntry(this);
140 m_pHeaderSection->Place(m_pCodeManagerEntry);
142 m_pImportSectionsTable = new (GetHeap()) ZapImportSectionsTable(this);
143 m_pImportTableSection->Place(m_pImportSectionsTable);
145 m_pExternalMethodDataTable = new (GetHeap()) ZapImportSectionSignatures(this, m_pExternalMethodThunkSection, m_pGCSection);
146 m_pExternalMethodDataSection->Place(m_pExternalMethodDataTable);
148 m_pStubDispatchDataTable = new (GetHeap()) ZapImportSectionSignatures(this, m_pStubDispatchCellSection, m_pGCSection);
149 m_pStubDispatchDataSection->Place(m_pStubDispatchDataTable);
151 m_pImportTable = new (GetHeap()) ZapImportTable(this);
153 m_pGCInfoTable = new (GetHeap()) ZapGCInfoTable(this);
154 m_pExceptionInfoLookupTable = new (GetHeap()) ZapExceptionInfoLookupTable(this);
156 #ifdef WIN64EXCEPTIONS
157 m_pUnwindDataTable = new (GetHeap()) ZapUnwindDataTable(this);
160 m_pEEInfoTable = ZapBlob::NewAlignedBlob(this, NULL, sizeof(CORCOMPILE_EE_INFO_TABLE), TARGET_POINTER_SIZE);
161 m_pEETableSection->Place(m_pEEInfoTable);
164 // Allocate Helper table, and fill it out
167 m_pHelperThunks = new (GetHeap()) ZapNode * [CORINFO_HELP_COUNT];
169 if (!m_zapper->m_pOpt->m_fNoMetaData)
171 m_pILMetaData = new (GetHeap()) ZapILMetaData(this);
172 m_pILMetaDataSection->Place(m_pILMetaData);
175 m_pDebugInfoTable = new (GetHeap()) ZapDebugInfoTable(this);
176 m_pDebugSection->Place(m_pDebugInfoTable);
178 m_pBaseRelocs = new (GetHeap()) ZapBaseRelocs(this);
179 m_pBaseRelocsSection->Place(m_pBaseRelocs);
181 SetDirectoryEntry(IMAGE_DIRECTORY_ENTRY_BASERELOC, m_pBaseRelocsSection);
184 // Initialization of auxiliary tables in alphabetical order
186 m_pInnerPtrs = new (GetHeap()) ZapInnerPtrTable(this);
187 m_pMethodEntryPoints = new (GetHeap()) ZapMethodEntryPointTable(this);
188 m_pWrappers = new (GetHeap()) ZapWrapperTable(this);
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);
195 #ifndef ZAP_HASHTABLE_TUNING
200 #ifdef FEATURE_READYTORUN_COMPILER
201 void ZapImage::InitializeSectionsForReadyToRun()
203 AllocateVirtualSections();
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;
209 m_pCorHeader = new (GetHeap()) ZapCorHeader(this);
210 m_pHeaderSection->Place(m_pCorHeader);
212 SetDirectoryEntry(IMAGE_DIRECTORY_ENTRY_COMHEADER, m_pCorHeader);
214 m_pNativeHeader = new (GetHeap()) ZapReadyToRunHeader(this);
215 m_pHeaderSection->Place(m_pNativeHeader);
217 m_pImportSectionsTable = new (GetHeap()) ZapImportSectionsTable(this);
218 m_pHeaderSection->Place(m_pImportSectionsTable);
221 #define COMPILER_NAME "CoreCLR"
223 const char * pCompilerIdentifier = COMPILER_NAME " " FX_FILEVERSION_STR " " QUOTE_MACRO(__BUILDMACHINE__);
224 ZapBlob * pCompilerIdentifierBlob = new (GetHeap()) ZapBlobPtr((PVOID)pCompilerIdentifier, strlen(pCompilerIdentifier) + 1);
226 GetReadyToRunHeader()->RegisterSection(READYTORUN_SECTION_COMPILER_IDENTIFIER, pCompilerIdentifierBlob);
227 m_pHeaderSection->Place(pCompilerIdentifierBlob);
230 m_pImportTable = new (GetHeap()) ZapImportTable(this);
232 for (int i=0; i<ZapImportSectionType_Total; i++)
234 ZapVirtualSection * pSection;
235 if (i == ZapImportSectionType_Eager)
236 pSection = m_pDelayLoadInfoDelayListSectionEager;
238 if (i < ZapImportSectionType_Cold)
239 pSection = m_pDelayLoadInfoDelayListSectionHot;
241 pSection = m_pDelayLoadInfoDelayListSectionCold;
243 m_pDelayLoadInfoDataTable[i] = new (GetHeap()) ZapImportSectionSignatures(this, m_pDelayLoadInfoTableSection[i]);
244 pSection->Place(m_pDelayLoadInfoDataTable[i]);
247 m_pDynamicHelperDataTable = new (GetHeap()) ZapImportSectionSignatures(this, m_pDynamicHelperCellSection);
248 m_pDynamicHelperDataSection->Place(m_pDynamicHelperDataTable);
250 m_pExternalMethodDataTable = new (GetHeap()) ZapImportSectionSignatures(this, m_pExternalMethodCellSection, m_pGCSection);
251 m_pExternalMethodDataSection->Place(m_pExternalMethodDataTable);
253 m_pStubDispatchDataTable = new (GetHeap()) ZapImportSectionSignatures(this, m_pStubDispatchCellSection, m_pGCSection);
254 m_pStubDispatchDataSection->Place(m_pStubDispatchDataTable);
256 m_pGCInfoTable = new (GetHeap()) ZapGCInfoTable(this);
258 #ifdef WIN64EXCEPTIONS
259 m_pUnwindDataTable = new (GetHeap()) ZapUnwindDataTable(this);
262 m_pILMetaData = new (GetHeap()) ZapILMetaData(this);
263 m_pILMetaDataSection->Place(m_pILMetaData);
265 m_pBaseRelocs = new (GetHeap()) ZapBaseRelocs(this);
266 m_pBaseRelocsSection->Place(m_pBaseRelocs);
268 SetDirectoryEntry(IMAGE_DIRECTORY_ENTRY_BASERELOC, m_pBaseRelocsSection);
271 // Initialization of auxiliary tables in alphabetical order
273 m_pInnerPtrs = new (GetHeap()) ZapInnerPtrTable(this);
275 m_pExceptionInfoLookupTable = new (GetHeap()) ZapExceptionInfoLookupTable(this);
278 // Always allocate slot for module - it is used to determine that the image is used
280 m_pImportTable->GetPlacedHelperImport(READYTORUN_HELPER_Module);
283 // Make sure the import sections table is in the image, so we can find the slot for module
285 _ASSERTE(m_pImportSectionsTable->GetSize() != 0);
286 GetReadyToRunHeader()->RegisterSection(READYTORUN_SECTION_IMPORT_SECTIONS, m_pImportSectionsTable);
288 #endif // FEATURE_READYTORUN_COMPILER
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
296 void ZapImage::AllocateVirtualSections()
299 // Allocate all virtual sections in the order they will appear in the final image
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.
310 DWORD access = DATA_MEM_WRITABLE;
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;
318 ZapPhysicalSection * pDataSection = NewPhysicalSection(".data", IMAGE_SCN_CNT_INITIALIZED_DATA | access);
320 m_pPreloadSections[CORCOMPILE_SECTION_MODULE] = NewVirtualSection(pDataSection, IBCUnProfiledSection | HotRange | ModuleSection);
322 m_pEETableSection = NewVirtualSection(pDataSection, IBCUnProfiledSection | HotRange | EETableSection); // Could be marked bss if it makes sense
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);
330 m_pPreloadSections[CORCOMPILE_SECTION_RVA_STATICS_HOT] = NewVirtualSection(pDataSection, IBCProfiledSection | HotRange | RVAStaticsSection);
332 m_pDelayLoadInfoTableSection[ZapImportSectionType_Eager] = NewVirtualSection(pDataSection, IBCUnProfiledSection | HotRange | DelayLoadInfoTableEagerSection, TARGET_POINTER_SIZE);
335 // Allocate dynamic info tables
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++)
341 m_pDelayLoadInfoTableSection[i] = NewVirtualSection(pDataSection, IBCProfiledSection | HotRange | DelayLoadInfoTableSection, TARGET_POINTER_SIZE);
344 m_pDynamicHelperCellSection = NewVirtualSection(pDataSection, IBCProfiledSection | HotColdSortedRange | ExternalMethodDataSection, TARGET_POINTER_SIZE);
346 m_pExternalMethodCellSection = NewVirtualSection(pDataSection, IBCProfiledSection | HotColdSortedRange | ExternalMethodThunkSection, TARGET_POINTER_SIZE);
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.
360 m_pStubDispatchCellSection = NewVirtualSection(pDataSection, IBCProfiledSection | HotColdSortedRange | StubDispatchDataSection, TARGET_POINTER_SIZE);
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++)
365 m_pDelayLoadInfoTableSection[ZapImportSectionType_Cold + i] = NewVirtualSection(pDataSection, IBCProfiledSection | ColdRange | DelayLoadInfoTableSection, TARGET_POINTER_SIZE);
369 // Virtual sections that are moved to .cdata when we have profile data.
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);
376 m_pPreloadSections[CORCOMPILE_SECTION_RVA_STATICS_COLD] = NewVirtualSection(pDataSection, IBCProfiledSection | ColdRange | RVAStaticsSection);
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);
389 // If we're instrumenting allocate a section for writing profile data
391 if (m_zapper->m_pOpt->m_compilerFlags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_BBINSTR))
393 m_pInstrumentSection = NewVirtualSection(pDataSection, IBCUnProfiledSection | ColdRange | InstrumentSection, TARGET_POINTER_SIZE);
397 // No RWX pages in ready to run images
398 if (!IsReadyToRunCompilation())
400 DWORD access = XDATA_MEM;
402 #ifdef FEATURE_LAZY_COW_PAGES
403 if (CLRConfig::GetConfigValue(CLRConfig::INTERNAL_ZapLazyCOWPagesEnabled))
410 ZapPhysicalSection * pXDataSection = NewPhysicalSection(".xdata", IMAGE_SCN_CNT_INITIALIZED_DATA | access);
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);
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);
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);
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;
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;
448 ZapPhysicalSection * pTextSection = NewPhysicalSection(".text", IMAGE_SCN_CNT_CODE | TEXT_MEM);
449 m_pTextSection = pTextSection;
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);
455 // Marked as a HotRange since it is always touched during Ngen image load.
456 m_pHeaderSection = NewVirtualSection(pTextSection, IBCUnProfiledSection | HotRange | HeaderSection);
458 // Marked as a HotRange since it is always touched during Ngen image binding.
459 m_pMetaDataSection = NewVirtualSection(pTextSection, IBCUnProfiledSection | HotRange | MetadataSection);
461 m_pImportTableSection = NewVirtualSection(pTextSection, IBCUnProfiledSection | HotRange | ImportTableSection, sizeof(DWORD));
463 m_pDelayLoadInfoDelayListSectionEager = NewVirtualSection(pTextSection, IBCUnProfiledSection | HotRange | DelayLoadInfoDelayListSection, sizeof(DWORD));
466 // GC Info for methods which were profiled hot AND had their GC Info touched during profiling
468 m_pHotTouchedGCSection = NewVirtualSection(pTextSection, IBCProfiledSection | HotRange | GCInfoSection, sizeof(DWORD));
470 m_pLazyHelperSection = NewVirtualSection(pTextSection, IBCUnProfiledSection | HotRange | HelperTableSection, MINIMUM_CODE_ALIGN);
471 m_pLazyHelperSection->SetDefaultFill(DEFAULT_CODE_BUFFER_INIT);
473 m_pLazyMethodCallHelperSection = NewVirtualSection(pTextSection, IBCUnProfiledSection | HotRange | HelperTableSection, MINIMUM_CODE_ALIGN);
474 m_pLazyMethodCallHelperSection->SetDefaultFill(DEFAULT_CODE_BUFFER_INIT);
476 int codeSectionAlign = DEFAULT_CODE_ALIGN;
478 m_pHotCodeSection = NewVirtualSection(pTextSection, IBCProfiledSection | HotRange | CodeSection, codeSectionAlign);
479 m_pHotCodeSection->SetDefaultFill(DEFAULT_CODE_BUFFER_INIT);
481 #if defined(WIN64EXCEPTIONS)
482 m_pHotUnwindDataSection = NewVirtualSection(pTextSection, IBCProfiledSection | HotRange | UnwindDataSection, sizeof(DWORD)); // .rdata area
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));
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)
494 m_pStubsSection = NewVirtualSection(pTextSection, IBCProfiledSection | HotColdSortedRange | StubsSection);
495 m_pReadOnlyDataSection = NewVirtualSection(pTextSection, IBCProfiledSection | HotColdSortedRange | ReadonlyDataSection);
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));
501 m_pHotRuntimeFunctionLookupSection = NewVirtualSection(pTextSection, IBCProfiledSection | HotRange | RuntimeFunctionSection, sizeof(DWORD));
502 #if !defined(WIN64EXCEPTIONS)
503 m_pHotRuntimeFunctionSection = NewVirtualSection(pTextSection, IBCProfiledSection | HotRange | RuntimeFunctionSection, sizeof(DWORD));
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)));
509 m_pHotCodeMethodDescsSection = NewVirtualSection(pTextSection, IBCProfiledSection | HotRange | CodeManagerSection, sizeof(DWORD));
511 m_pDelayLoadInfoDelayListSectionHot = NewVirtualSection(pTextSection, IBCProfiledSection | HotRange | DelayLoadInfoDelayListSection, sizeof(DWORD));
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.
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);
525 // GC Info for methods which were touched during profiling but didn't explicitly have
526 // their GC Info touched during profiling
528 m_pHotGCSection = NewVirtualSection(pTextSection, IBCProfiledSection | WarmRange | GCInfoSection, sizeof(DWORD));
530 #if !defined(_TARGET_ARM_)
531 // For ARM, put these sections more towards the end because bl/b instructions have limited diplacement
534 m_pILSection = NewVirtualSection(pTextSection, IBCProfiledSection | HotColdSortedRange | ILSection, sizeof(DWORD));
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_
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
543 m_pResourcesSection = NewVirtualSection(pTextSection, IBCUnProfiledSection | WarmRange | ResourcesSection);
546 // Allocate the unprofiled code section and code manager nibble map here
548 m_pCodeSection = NewVirtualSection(pTextSection, IBCProfiledSection | WarmRange | ColdRange | CodeSection, codeSectionAlign);
549 m_pCodeSection->SetDefaultFill(DEFAULT_CODE_BUFFER_INIT);
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));
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)));
559 m_pCodeMethodDescsSection = NewVirtualSection(pTextSection, IBCProfiledSection | WarmRange | ColdRange | CodeHeaderSection,sizeof(DWORD));
561 #ifdef FEATURE_READYTORUN_COMPILER
562 if (IsReadyToRunCompilation())
564 m_pAvailableTypesSection = NewVirtualSection(pTextSection, IBCUnProfiledSection | WarmRange | ReadonlySection);
565 m_pAttributePresenceSection = NewVirtualSection(pTextSection, IBCUnProfiledSection | WarmRange | ReadonlyDataSection, 16/* Must be 16 byte aligned */);
569 #if defined(WIN64EXCEPTIONS)
570 m_pUnwindDataSection = NewVirtualSection(pTextSection, IBCProfiledSection | WarmRange | ColdRange | UnwindDataSection, sizeof(DWORD));
571 #endif // defined(WIN64EXCEPTIONS)
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);
578 // GC Info for methods which were not touched in profiling
580 m_pGCSection = NewVirtualSection(pTextSection, IBCProfiledSection | ColdRange | GCInfoSection, sizeof(DWORD));
582 m_pDelayLoadInfoDelayListSectionCold = NewVirtualSection(pTextSection, IBCProfiledSection | ColdRange | DelayLoadInfoDelayListSection, sizeof(DWORD));
584 m_pPreloadSections[CORCOMPILE_SECTION_READONLY_COLD] = NewVirtualSection(pTextSection, IBCProfiledSection | ColdRange | ReadonlySection, TARGET_POINTER_SIZE);
587 // Allocate the cold code section near the end of the image
589 m_pColdCodeSection = NewVirtualSection(pTextSection, IBCProfiledSection | IBCUnProfiledSection | ColdRange | CodeSection, codeSectionAlign);
590 m_pColdCodeSection->SetDefaultFill(DEFAULT_CODE_BUFFER_INIT);
592 #if defined(_TARGET_ARM_)
593 // For ARM, put these sections more towards the end because bl/b instructions have limited diplacement
596 m_pILSection = NewVirtualSection(pTextSection, IBCProfiledSection | HotColdSortedRange | ILSection, sizeof(DWORD));
598 //ILMetadata/Resources sections are reported as a statically known warm ranges for now.
599 m_pILMetaDataSection = NewVirtualSection(pTextSection, IBCProfiledSection | HotColdSortedRange | ILMetadataSection, sizeof(DWORD));
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));
606 #if !defined(WIN64EXCEPTIONS)
607 m_pColdRuntimeFunctionSection = NewVirtualSection(pTextSection, IBCProfiledSection | IBCUnProfiledSection | ColdRange | RuntimeFunctionSection, sizeof(DWORD));
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)));
614 #if defined(WIN64EXCEPTIONS)
615 m_pColdUnwindDataSection = NewVirtualSection(pTextSection, IBCProfiledSection | IBCUnProfiledSection | ColdRange | UnwindDataSection, sizeof(DWORD));
616 #endif // defined(WIN64EXCEPTIONS)
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.
625 m_pPreloadSections[CORCOMPILE_SECTION_COMPRESSED_MAPS] = NewVirtualSection(pTextSection, IBCProfiledSection | ColdRange | CompressedMapsSection, sizeof(DWORD));
627 m_pExceptionSection = NewVirtualSection(pTextSection, IBCProfiledSection | HotColdSortedRange | ExceptionSection, sizeof(DWORD));
630 // Debug info is sometimes used during exception handling to build stacktrace
632 m_pDebugSection = NewVirtualSection(pTextSection, IBCUnProfiledSection | ColdRange | DebugSection, sizeof(DWORD));
640 ZapPhysicalSection * pRelocSection = NewPhysicalSection(".reloc", IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_DISCARDABLE | IMAGE_SCN_MEM_READ);
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);
649 void ZapImage::Preallocate()
651 COUNT_T cbILImage = m_ModuleDecoder.GetSize();
653 // Curb the estimate to handle corner cases gracefuly
654 cbILImage = min(cbILImage, 50000000);
656 PREALLOCATE_HASHTABLE(ZapImage::m_CompiledMethods, 0.0050, cbILImage);
657 PREALLOCATE_HASHTABLE(ZapImage::m_ClassLayoutOrder, 0.0003, cbILImage);
660 // Preallocation of auxiliary tables in alphabetical order
662 m_pImportTable->Preallocate(cbILImage);
663 m_pInnerPtrs->Preallocate(cbILImage);
664 m_pMethodEntryPoints->Preallocate(cbILImage);
665 m_pWrappers->Preallocate(cbILImage);
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);
676 void ZapImage::SetVersionInfo(CORCOMPILE_VERSION_INFO * pVersionInfo)
678 m_pVersionInfo = new (GetHeap()) ZapVersionInfo(pVersionInfo);
679 m_pHeaderSection->Place(m_pVersionInfo);
682 void ZapImage::SetDependencies(CORCOMPILE_DEPENDENCY *pDependencies, DWORD cDependencies)
684 m_pDependencies = new (GetHeap()) ZapDependencies(pDependencies, cDependencies);
685 m_pHeaderSection->Place(m_pDependencies);
688 void ZapImage::SetPdbFileName(const SString &strFileName)
690 m_pdbFileName.Set(strFileName);
693 #ifdef WIN64EXCEPTIONS
694 void ZapImage::SetRuntimeFunctionsDirectoryEntry()
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.
700 ZapVirtualSection * rgRuntimeFunctionSections[] = {
701 m_pHotRuntimeFunctionSection,
702 m_pRuntimeFunctionSection,
703 m_pColdRuntimeFunctionSection
706 DWORD dwTotalSize = 0, dwStartRVA = (DWORD)-1, dwEndRVA = 0;
708 for (size_t i = 0; i < _countof(rgRuntimeFunctionSections); i++)
710 ZapVirtualSection * pSection = rgRuntimeFunctionSections[i];
712 DWORD dwSize = pSection->GetSize();
716 DWORD dwRVA = pSection->GetRVA();
718 dwTotalSize += dwSize;
720 dwStartRVA = min(dwStartRVA, dwRVA);
721 dwEndRVA = max(dwEndRVA, dwRVA + dwSize);
724 if (dwTotalSize != 0)
726 // Verify that there are no holes between the sections
727 _ASSERTE(dwStartRVA + dwTotalSize == dwEndRVA);
729 ZapNode * pAllRuntimeFunctionSections = new (GetHeap()) ZapDummyNode(dwTotalSize);
730 pAllRuntimeFunctionSections->SetRVA(dwStartRVA);
732 // Write the address of the sorted pdata to the optionalHeader.DataDirectory
733 SetDirectoryEntry(IMAGE_DIRECTORY_ENTRY_EXCEPTION, pAllRuntimeFunctionSections);
736 #endif // WIN64EXCEPTIONS
738 // Assign RVAs to all ZapNodes
739 void ZapImage::ComputeRVAs()
741 ZapWriter::ComputeRVAs();
743 if (!IsReadyToRunCompilation())
745 m_pMethodEntryPoints->Resolve();
746 m_pWrappers->Resolve();
749 m_pInnerPtrs->Resolve();
751 #ifdef WIN64EXCEPTIONS
752 SetRuntimeFunctionsDirectoryEntry();
756 #ifdef FEATURE_SYMDIFF
757 if (CLRConfig::GetConfigValue(CLRConfig::INTERNAL_SymDiffDump))
759 COUNT_T curMethod = 0;
760 COUNT_T numMethods = m_MethodCompilationOrder.GetCount();
762 for (; curMethod < numMethods; curMethod++)
765 //if(curMethod >= m_iUntrainedMethod) fCold = true;
767 ZapMethodHeader * pMethod = m_MethodCompilationOrder[curMethod];
769 ZapBlobWithRelocs * pCode = fCold ? pMethod->m_pColdCode : pMethod->m_pCode;
774 CORINFO_METHOD_HANDLE handle = pMethod->GetHandle();
776 GetCompileInfo()->GetMethodDef(handle, &token);
777 GetSvcLogger()->Printf(W("(EntryPointRVAMap (MethodToken %0X) (RVA %0X) (SIZE %0X))\n"), token, pCode->GetRVA(), pCode->GetSize());
781 #endif // FEATURE_SYMDIFF
785 class ZapFileStream : public IStream
792 : m_hFile(INVALID_HANDLE_VALUE)
802 void SetHandle(HANDLE hFile)
804 _ASSERTE(m_hFile == INVALID_HANDLE_VALUE);
809 STDMETHODIMP_(ULONG) AddRef()
814 STDMETHODIMP_(ULONG) Release()
819 STDMETHODIMP QueryInterface(REFIID riid, LPVOID *ppv)
822 if (IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_IStream)) {
823 *ppv = static_cast<IStream *>(this);
831 // ISequentialStream methods:
832 STDMETHODIMP Read(void *pv, ULONG cb, ULONG *pcbRead)
838 STDMETHODIMP Write(void const *pv, ULONG cb, ULONG *pcbWritten)
842 _ASSERTE(m_hFile != INVALID_HANDLE_VALUE);
844 m_hasher.HashMore(pv, cb);
846 // We are calling with lpOverlapped == NULL so pcbWritten has to be present
847 // to prevent crashes in Win7 and below.
848 _ASSERTE(pcbWritten);
850 if (!::WriteFile(m_hFile, pv, cb, pcbWritten, NULL))
852 hr = HRESULT_FROM_GetLastError();
861 STDMETHODIMP Seek(LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition)
865 _ASSERTE(m_hFile != INVALID_HANDLE_VALUE);
869 case STREAM_SEEK_SET:
870 dwFileOrigin = FILE_BEGIN;
873 case STREAM_SEEK_CUR:
874 dwFileOrigin = FILE_CURRENT;
877 case STREAM_SEEK_END:
878 dwFileOrigin = FILE_END;
885 if (!::SetFilePointerEx(m_hFile, dlibMove, (LARGE_INTEGER *)plibNewPosition, dwFileOrigin))
887 hr = HRESULT_FROM_GetLastError();
895 STDMETHODIMP SetSize(ULARGE_INTEGER libNewSize)
899 _ASSERTE(m_hFile != INVALID_HANDLE_VALUE);
901 hr = Seek(*(LARGE_INTEGER *)&libNewSize, FILE_BEGIN, NULL);
907 if (!::SetEndOfFile(m_hFile))
909 hr = HRESULT_FROM_GetLastError();
917 STDMETHODIMP CopyTo(IStream *pstm, ULARGE_INTEGER cb, ULARGE_INTEGER *pcbRead, ULARGE_INTEGER *pcbWritten)
923 STDMETHODIMP Commit(DWORD grfCommitFlags)
929 STDMETHODIMP Revert()
935 STDMETHODIMP LockRegion(ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType)
941 STDMETHODIMP UnlockRegion(ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType)
947 STDMETHODIMP Stat(STATSTG *pstatstg, DWORD grfStatFlag)
953 STDMETHODIMP Clone(IStream **ppIStream)
963 HANDLE hFile = m_hFile;
964 if (hFile != INVALID_HANDLE_VALUE)
966 m_hFile = INVALID_HANDLE_VALUE;
968 if (!::CloseHandle(hFile))
970 hr = HRESULT_FROM_GetLastError();
981 m_hFile = INVALID_HANDLE_VALUE;
984 void GetHash(MD5HASHDATA* pHash)
986 m_hasher.GetHashValue(pHash);
990 HANDLE ZapImage::GenerateFile(LPCWSTR wszOutputFileName, CORCOMPILE_NGEN_SIGNATURE * pNativeImageSig)
992 ZapFileStream outputStream;
994 HANDLE hFile = WszCreateFile(wszOutputFileName,
995 GENERIC_READ | GENERIC_WRITE,
996 FILE_SHARE_READ | FILE_SHARE_DELETE,
999 FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,
1002 if (hFile == INVALID_HANDLE_VALUE)
1005 outputStream.SetHandle(hFile);
1007 Save(&outputStream);
1009 LARGE_INTEGER filePos;
1011 if (m_pNativeHeader != NULL)
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);
1021 GUID signature = {0};
1023 static_assert_no_msg(sizeof(GUID) == sizeof(MD5HASHDATA));
1024 outputStream.GetHash((MD5HASHDATA*)&signature);
1027 // Write the debug directory entry for the NGEN PDB
1030 rsds.magic = VAL32(0x53445352); // "SDSR";
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.
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);
1043 _ASSERTE(!m_pdbFileName.IsEmpty());
1044 ZeroMemory(&rsds.path[0], sizeof(rsds.path));
1045 if (WideCharToMultiByte(CP_UTF8,
1047 m_pdbFileName.GetUnicode(),
1048 m_pdbFileName.GetCount(),
1050 sizeof(rsds.path) - 1, // -1 to keep the buffer zero terminated
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));
1061 if (m_pVersionInfo != NULL)
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));
1071 if (pNativeImageSig != NULL)
1072 *pNativeImageSig = signature;
1076 _ASSERTE(pNativeImageSig == NULL);
1079 outputStream.SuppressClose();
1084 HANDLE ZapImage::SaveImage(LPCWSTR wszOutputFileName, LPCWSTR wszDllPath, CORCOMPILE_NGEN_SIGNATURE * pNativeImageSig)
1086 if(!IsReadyToRunCompilation() || IsLargeVersionBubbleEnabled())
1088 OutputManifestMetadata();
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);
1103 if (!IsReadyToRunCompilation())
1105 m_pPreloader->FixupRVAs();
1108 HANDLE hFile = GenerateFile(wszOutputFileName, pNativeImageSig);
1110 if (m_zapper->m_pOpt->m_verbose)
1112 PrintStats(wszOutputFileName);
1118 void ZapImage::PrintStats(LPCWSTR wszOutputFileName)
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)
1132 // Get the size of the input & output files
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;
1143 WIN32_FIND_DATA outputData;
1144 FindHandleHolder outputHandle = WszFindFirstFile(wszOutputFileName, &outputData);
1145 if (outputHandle != INVALID_HANDLE_VALUE)
1146 m_stats->m_outputFileSize = outputData.nFileSizeLow;
1149 ACCUM_SIZE(m_stats->m_metadataSize, m_pAssemblyMetaData);
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;
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);
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);
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);
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);
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();
1190 // Align native images to 64K
1191 const SIZE_T BASE_ADDRESS_ALIGNMENT = 0xffff;
1192 const double CODE_EXPANSION_FACTOR = 3.6;
1194 void ZapImage::CalculateZapBaseAddress()
1196 static SIZE_T nextBaseAddressForMultiModule;
1198 SIZE_T baseAddress = 0;
1201 // Read the actual preferred base address from the disk
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,
1207 FILE_SHARE_READ|FILE_SHARE_DELETE,
1210 FILE_ATTRIBUTE_NORMAL,
1212 if (hFile == INVALID_HANDLE_VALUE)
1215 HandleHolder hFileMap(WszCreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL));
1216 if (hFileMap == NULL)
1219 MapViewHolder base(MapViewOfFile(hFileMap, FILE_MAP_READ, 0, 0, 0));
1223 DWORD dwFileLen = SafeGetFileSize(hFile, 0);
1224 if (dwFileLen == INVALID_FILE_SIZE)
1227 PEDecoder peFlat((void *)base, (COUNT_T)dwFileLen);
1229 baseAddress = (SIZE_T) peFlat.GetPreferredBase();
1232 // See if the header has the linker's default preferred base address
1233 if (baseAddress == (SIZE_T) 0x00400000)
1235 if (m_fManifestModule)
1237 // Set the base address for the main assembly with the manifest
1239 if (!m_ModuleDecoder.IsDll())
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;
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;
1262 else // is dependent assembly of a multi-module assembly
1264 // Set the base address for a dependant multi module assembly
1266 // We should have already set the nextBaseAddressForMultiModule
1267 // when we compiled the manifest module
1268 _ASSERTE(nextBaseAddressForMultiModule != 0);
1269 baseAddress = nextBaseAddressForMultiModule;
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.
1278 // CoreCLR currently always loads both the IL and the native image, so
1279 // move the native image out of the way.
1281 baseAddress += m_ModuleDecoder.GetVirtualSize();
1285 if (m_zapper->GetCustomBaseAddress() != 0)
1287 //set baseAddress here from crossgen options
1288 baseAddress = m_zapper->GetCustomBaseAddress();
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
1296 baseAddress = (baseAddress + BASE_ADDRESS_ALIGNMENT) & ~BASE_ADDRESS_ALIGNMENT;
1299 // Calculate the nextBaseAddressForMultiModule
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;
1306 nextBaseAddressForMultiModule = tempBaseAddress;
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
1312 #if USE_UPPER_ADDRESS
1313 #if defined(_TARGET_64BIT_)
1314 if (baseAddress < 0x80000000)
1316 if (baseAddress < 0x40000000)
1317 baseAddress += 0x40000000; // We map [00000000..3fffffff] to [642'80000000..642'ffffffff]
1319 baseAddress -= 0x40000000; // We map [40000000..7fffffff] to [642'00000000..642'7fffffff]
1321 baseAddress *= UPPER_ADDRESS_MAPPING_FACTOR;
1322 baseAddress += CLR_UPPER_ADDRESS_MIN;
1328 // Apply the calculated base address.
1329 SetBaseAddress(baseAddress);
1331 m_NativeBaseAddress = baseAddress;
1334 void ZapImage::Open(CORINFO_MODULE_HANDLE hModule,
1335 IMetaDataAssemblyEmit *pEmit)
1337 m_hModule = hModule;
1338 m_fManifestModule = (hModule == m_zapper->m_pEECompileInfo->GetAssemblyModule(m_zapper->m_hAssembly));
1340 m_ModuleDecoder = *m_zapper->m_pEECompileInfo->GetModuleDecoder(hModule);
1344 // Get file name, and base address from module
1347 StackSString moduleFileName;
1348 m_zapper->m_pEECompileInfo->GetModuleFileName(hModule, moduleFileName);
1350 DWORD fileNameLength = moduleFileName.GetCount();
1351 m_pModuleFileName = new WCHAR[fileNameLength+1];
1352 wcscpy_s(m_pModuleFileName, fileNameLength+1, moduleFileName.GetUnicode());
1355 // Load the IBC Profile data for the assembly if it exists
1360 // Get metadata of module to be compiled
1362 m_pMDImport = m_zapper->m_pEECompileInfo->GetModuleMetaDataImport(m_hModule);
1363 _ASSERTE(m_pMDImport != NULL);
1366 // Open new assembly metadata data for writing. We may not use it,
1367 // if so we'll just discard it at the end.
1372 m_pAssemblyEmit = pEmit;
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));
1384 IfFailThrow(m_zapper->m_pMetaDataDispenser->
1385 DefineScope(CLSID_CorMetaDataRuntime, 0, IID_IMetaDataAssemblyEmit,
1386 (IUnknown **) &m_pAssemblyEmit));
1389 #ifdef FEATURE_READYTORUN_COMPILER
1390 if (IsReadyToRunCompilation())
1392 InitializeSectionsForReadyToRun();
1397 InitializeSections();
1400 // Set the module base address for the ngen native image
1401 CalculateZapBaseAddress();
1408 // Load the module and populate all the data-structures
1411 void ZapImage::Preload()
1414 CorProfileData * pProfileData = NewProfileData();
1415 m_pPreloader = m_zapper->m_pEECompileInfo->PreloadModule(m_hModule, this, pProfileData);
1422 void ZapImage::LinkPreload()
1424 m_pPreloader->Link();
1427 void ZapImage::OutputManifestMetadata()
1430 // Write out manifest metadata
1434 // First, see if we have useful metadata to store
1437 BOOL fMetadata = FALSE;
1439 if (m_pAssemblyEmit != NULL)
1442 // We may have added some assembly refs for exports.
1445 NonVMComHolder<IMetaDataAssemblyImport> pAssemblyImport;
1446 IfFailThrow(m_pAssemblyEmit->QueryInterface(IID_IMetaDataAssemblyImport,
1447 (void **)&pAssemblyImport));
1449 NonVMComHolder<IMetaDataImport> pImport;
1450 IfFailThrow(m_pAssemblyEmit->QueryInterface(IID_IMetaDataImport,
1451 (void **)&pImport));
1455 IfFailThrow(pAssemblyImport->EnumAssemblyRefs(&hEnum, NULL, 0, &cRefs));
1456 IfFailThrow(pImport->CountEnum(hEnum, &cRefs));
1457 pImport->CloseEnum(hEnum);
1463 // If we are the main module, we have the assembly def for the zap file.
1467 if (pAssemblyImport->GetAssemblyFromScope(&a) == S_OK)
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.
1477 NonVMComHolder<IMDInternalEmit> pMDInternalEmit;
1478 IfFailThrow(m_pAssemblyEmit->QueryInterface(IID_IMDInternalEmit,
1479 (void**)&pMDInternalEmit));
1481 IfFailThrow(pMDInternalEmit->ChangeMvid(NGEN_IMAGE_MVID));
1483 m_pAssemblyMetaData = new (GetHeap()) ZapMetaData();
1484 m_pAssemblyMetaData->SetMetaData(m_pAssemblyEmit);
1486 m_pMetaDataSection->Place(m_pAssemblyMetaData);
1490 void ZapImage::OutputTables()
1493 // Copy over any resources to the native image
1497 PVOID resource = (PVOID)m_ModuleDecoder.GetResources(&size);
1501 m_pResources = new (GetHeap()) ZapBlobPtr(resource, size);
1502 m_pResourcesSection->Place(m_pResources);
1505 CopyDebugDirEntry();
1506 CopyWin32Resources();
1508 if (m_pILMetaData != NULL)
1510 m_pILMetaData->CopyIL();
1511 m_pILMetaData->CopyMetaData();
1514 if (IsReadyToRunCompilation())
1516 m_pILMetaData->CopyRVAFields();
1519 // Copy over the timestamp from IL image for determinism
1520 SetTimeDateStamp(m_ModuleDecoder.GetTimeDateStamp());
1522 SetSubsystem(m_ModuleDecoder.GetSubsystem());
1525 USHORT dllCharacteristics = 0;
1527 #ifndef _TARGET_64BIT_
1528 dllCharacteristics |= IMAGE_DLLCHARACTERISTICS_NO_SEH;
1532 // Images without NX compat bit set fail to load on ARM
1533 dllCharacteristics |= IMAGE_DLLCHARACTERISTICS_NX_COMPAT;
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));
1541 if (0 == CLRConfig::GetConfigValue(CLRConfig::INTERNAL_NoASLRForNgen))
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;
1551 SetDllCharacteristics(dllCharacteristics);
1554 if (IsReadyToRunCompilation())
1557 SetSizeOfStackReserve(m_ModuleDecoder.GetSizeOfStackReserve());
1558 SetSizeOfStackCommit(m_ModuleDecoder.GetSizeOfStackCommit());
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())
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);
1574 ZapImage::CompileStatus ZapImage::CompileProfileDataWorker(mdToken token, unsigned methodProfilingDataFlags)
1576 if ((TypeFromToken(token) != mdtMethodDef) ||
1577 (!m_pMDImport->IsValidToken(token)))
1579 m_zapper->Info(W("Warning: Invalid method token %08x in profile data.\n"), token);
1580 return NOT_COMPILED;
1584 static ConfigDWORD g_NgenOrder;
1586 if ((g_NgenOrder.val(CLRConfig::INTERNAL_NgenOrder) & 2) == 2)
1588 const ProfileDataHashEntry * foundEntry = profileDataHashTable.LookupPtr(token);
1590 if (foundEntry == NULL)
1591 return NOT_COMPILED;
1593 // The md must match.
1594 _ASSERTE(foundEntry->md == token);
1595 // The target position cannot be 0.
1596 _ASSERTE(foundEntry->pos > 0);
1600 // Now compile the method
1601 return TryCompileMethodDef(token, methodProfilingDataFlags);
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.
1609 void ZapImage::ProfileDisableInlining()
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.
1615 ProfileDataSection* methodProfileData = &(m_profileDataSections[MethodProfilingData]);
1616 if (methodProfileData->tableSize > 0)
1618 for (DWORD i = 0; i < methodProfileData->tableSize; i++)
1620 CORBBTPROF_TOKEN_INFO * pTokenInfo = &(methodProfileData->pTable[i]);
1621 unsigned methodProfilingDataFlags = pTokenInfo->flags;
1623 // Hot methods can be marked to be excluded from the AOT native image.
1624 // We also need to disable inlining of such methods.
1626 if ((methodProfilingDataFlags & (1 << DisableInlining)) != 0)
1628 // Disable the inlining of this method
1630 // @ToDo: Figure out how to disable inlining for this method.
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.
1641 void ZapImage::CompileHotRegion()
1643 // Compile all of the methods that were executed during profiling into the "Hot" code region.
1645 BeginRegion(CORINFO_REGION_HOT);
1647 CorProfileData* pProfileData = GetProfileData();
1649 ProfileDataSection* methodProfileData = &(m_profileDataSections[MethodProfilingData]);
1650 if (methodProfileData->tableSize > 0)
1652 // record the start of hot IBC methods.
1653 m_iIBCMethod = m_MethodCompilationOrder.GetCount();
1656 // Compile the hot methods in the order specified in the MethodProfilingData
1658 for (DWORD i = 0; i < methodProfileData->tableSize; i++)
1660 CompileStatus compileResult = NOT_COMPILED;
1661 CORBBTPROF_TOKEN_INFO * pTokenInfo = &(methodProfileData->pTable[i]);
1663 mdToken token = pTokenInfo->token;
1664 unsigned methodProfilingDataFlags = pTokenInfo->flags;
1665 _ASSERTE(methodProfilingDataFlags != 0);
1667 if (TypeFromToken(token) == mdtMethodDef)
1670 // Compile a non-generic method
1672 compileResult = CompileProfileDataWorker(token, methodProfilingDataFlags);
1674 else if (TypeFromToken(token) == ibcMethodSpec)
1677 // compile a generic/parameterized method
1679 CORBBTPROF_BLOB_PARAM_SIG_ENTRY *pBlobSigEntry = pProfileData->GetBlobSigEntry(token);
1681 if (pBlobSigEntry == NULL)
1683 m_zapper->Info(W("Warning: Did not find definition for method token %08x in profile data.\n"), token);
1685 else // (pBlobSigEntry != NULL)
1687 _ASSERTE(pBlobSigEntry->blob.token == token);
1689 // decode method desc
1690 CORINFO_METHOD_HANDLE pMethod = m_pPreloader->FindMethodForProfileEntry(pBlobSigEntry);
1694 m_pPreloader->AddMethodToTransitiveClosureOfInstantiations(pMethod);
1696 compileResult = TryCompileInstantiatedMethod(pMethod, methodProfilingDataFlags);
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.
1705 compileResult = COMPILE_EXCLUDED;
1710 // Update the 'flags' and 'compileResult' saved in the profileDataHashTable hash table.
1712 hashBBUpdateFlagsAndCompileResult(token, methodProfilingDataFlags, compileResult);
1714 // record the start of hot Generics methods.
1715 m_iGenericsMethod = m_MethodCompilationOrder.GetCount();
1718 // record the start of untrained code
1719 m_iUntrainedMethod = m_MethodCompilationOrder.GetCount();
1721 EndRegion(CORINFO_REGION_HOT);
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.
1729 void ZapImage::CompileColdRegion()
1731 // Compile all of the methods that were NOT executed during profiling into the "Cold" code region.
1734 BeginRegion(CORINFO_REGION_COLD);
1736 IMDInternalImport * pMDImport = m_pMDImport;
1738 HENUMInternalHolder hEnum(pMDImport);
1739 hEnum.EnumAllInit(mdtMethodDef);
1742 while (pMDImport->EnumNext(&hEnum, &md))
1745 // Compile the remaining methods that weren't compiled during the CompileHotRegion phase
1747 TryCompileMethodDef(md, 0);
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)
1755 TryCompileInstantiatedMethod(handle, 0);
1756 handle = m_pPreloader->NextUncompiledMethod();
1759 EndRegion(CORINFO_REGION_COLD);
1763 // Copy the IL for all method into the AOT native image
1765 void ZapImage::PlaceMethodIL()
1767 // Place the IL for all of the methods
1769 IMDInternalImport * pMDImport = m_pMDImport;
1770 HENUMInternalHolder hEnum(pMDImport);
1771 hEnum.EnumAllInit(mdtMethodDef);
1774 while (pMDImport->EnumNext(&hEnum, &md))
1776 if (m_pILMetaData != NULL)
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.
1782 m_pILMetaData->EmitMethodIL(md);
1787 void ZapImage::Compile()
1790 // Compile all of the methods for our AOT native image
1793 bool doNothingNgen = false;
1795 static ConfigDWORD fDoNothingNGen;
1796 doNothingNgen = !!fDoNothingNGen.val(CLRConfig::INTERNAL_ZapDoNothing);
1799 ProfileDisableInlining();
1805 CompileColdRegion();
1810 // Compute a preferred class layout order based on analyzing the graph
1811 // of which classes contain calls to other classes.
1812 ComputeClassLayoutOrder();
1814 // Sort the unprofiled methods by this preferred class layout, if available
1815 if (m_fHasClassLayoutOrder)
1817 SortUnprofiledMethodsByClassLayoutOrder();
1820 if (IsReadyToRunCompilation())
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;
1827 OutputCode(ProfiledHot);
1828 OutputCode(Unprofiled);
1829 OutputCode(ProfiledCold);
1831 OutputCodeInfo(ProfiledHot);
1832 OutputCodeInfo(ProfiledCold); // actually both Unprofiled and ProfiledCold
1835 OutputProfileData();
1837 #ifdef FEATURE_READYTORUN_COMPILER
1838 if (IsReadyToRunCompilation())
1840 OutputEntrypointsTableForReadyToRun();
1841 OutputDebugInfoForReadyToRun();
1842 OutputTypesTableForReadyToRun(m_pMDImport);
1843 OutputAttributePresenceFilter(m_pMDImport);
1844 OutputInliningTableForReadyToRun();
1845 OutputProfileDataForReadyToRun();
1846 if (IsLargeVersionBubbleEnabled())
1848 OutputManifestMetadataForReadyToRun();
1858 struct CompileMethodStubContext
1861 unsigned methodProfilingDataFlags;
1862 ZapImage::CompileStatus enumCompileStubResult;
1864 CompileMethodStubContext(ZapImage * _image, unsigned _methodProfilingDataFlags)
1867 methodProfilingDataFlags = _methodProfilingDataFlags;
1868 enumCompileStubResult = ZapImage::NOT_COMPILED;
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 //-----------------------------------------------------------------------------
1880 // static void __stdcall
1881 void ZapImage::TryCompileMethodStub(LPVOID pContext, CORINFO_METHOD_HANDLE hStub, CORJIT_FLAGS jitFlags)
1883 STANDARD_VM_CONTRACT;
1885 // The caller must always set the IL_STUB flag
1886 _ASSERTE(jitFlags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_IL_STUB));
1888 CompileMethodStubContext *pCompileContext = reinterpret_cast<CompileMethodStubContext *>(pContext);
1889 ZapImage *pImage = pCompileContext->pImage;
1891 CORJIT_FLAGS oldFlags = pImage->m_zapper->m_pOpt->m_compilerFlags;
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);
1900 mdMethodDef md = mdMethodDefNil;
1902 pCompileContext->enumCompileStubResult = pImage->TryCompileMethodWorker(hStub, md,
1903 pCompileContext->methodProfilingDataFlags);
1905 pImage->m_zapper->m_pOpt->m_compilerFlags = oldFlags;
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)
1915 #ifdef FEATURE_COMINTEROP
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))
1927 // Now check the name of the method. All vtable gap methods will have a prefix of "_VtblGap".
1929 PCCOR_SIGNATURE pvSigBlob;
1931 hr = m_pMDImport->GetNameAndSigOfMethodDef(md, &pvSigBlob, &cbSigBlob, &szMethod);
1932 if (FAILED(hr) || (strncmp(szMethod, "_VtblGap", 8) != 0))
1935 // If we make it to here we have a vtable gap method.
1939 #endif // FEATURE_COMINTEROP
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 //-----------------------------------------------------------------------------
1948 ZapImage::CompileStatus ZapImage::TryCompileMethodDef(mdMethodDef md, unsigned methodProfilingDataFlags)
1950 _ASSERTE(!IsNilToken(md));
1952 CORINFO_METHOD_HANDLE handle = NULL;
1953 CompileStatus result = NOT_COMPILED;
1955 if (ShouldCompileMethodDef(md))
1957 handle = m_pPreloader->LookupMethodDef(md);
1958 if (handle == nullptr)
1960 result = LOOKUP_FAILED;
1965 result = COMPILE_EXCLUDED;
1971 // compile the method
1973 CompileStatus methodCompileStatus = TryCompileMethodWorker(handle, md, methodProfilingDataFlags);
1975 // Don't bother compiling the IL_STUBS if we failed to compile the parent IL method
1977 if (methodCompileStatus == COMPILE_SUCCEED)
1979 CompileMethodStubContext context(this, methodProfilingDataFlags);
1981 // compile stubs associated with the method
1982 m_pPreloader->GenerateMethodStubs(handle, m_zapper->m_pOpt->m_ngenProfileImage,
1983 &TryCompileMethodStub,
1987 return methodCompileStatus;
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 //-----------------------------------------------------------------------------
1996 ZapImage::CompileStatus ZapImage::TryCompileInstantiatedMethod(CORINFO_METHOD_HANDLE handle,
1997 unsigned methodProfilingDataFlags)
1999 if (IsReadyToRunCompilation())
2001 if (!GetCompileInfo()->IsInCurrentVersionBubble(m_zapper->m_pEEJitInfo->getMethodModule(handle)))
2002 return COMPILE_EXCLUDED;
2005 if (!ShouldCompileInstantiatedMethod(handle))
2006 return COMPILE_EXCLUDED;
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
2011 if (methodProfilingDataFlags != 0)
2013 if (methodProfilingDataFlags & (1 << ReadMethodCode))
2015 // When we have stale IBC data the method could have been rejected from this image.
2016 if (!m_pPreloader->IsUncompiledMethod(handle))
2018 const char* szClsName;
2019 const char* szMethodName = m_zapper->m_pEEJitInfo->getMethodName(handle, &szClsName);
2021 SString fullname(SString::Utf8, szClsName);
2022 fullname.AppendUTF8(NAMESPACE_SEPARATOR_STR);
2023 fullname.AppendUTF8(szMethodName);
2025 m_zapper->Info(W("Warning: Invalid method instantiation in profile data: %s\n"), fullname.GetUnicode());
2027 return NOT_COMPILED;
2032 CompileStatus methodCompileStatus = TryCompileMethodWorker(handle, mdMethodDefNil, methodProfilingDataFlags);
2034 // Don't bother compiling the IL_STUBS if we failed to compile the parent IL method
2036 if (methodCompileStatus == COMPILE_SUCCEED)
2038 CompileMethodStubContext context(this, methodProfilingDataFlags);
2040 // compile stubs associated with the method
2041 m_pPreloader->GenerateMethodStubs(handle, m_zapper->m_pOpt->m_ngenProfileImage,
2042 &TryCompileMethodStub,
2046 return methodCompileStatus;
2049 //-----------------------------------------------------------------------------
2051 ZapImage::CompileStatus ZapImage::TryCompileMethodWorker(CORINFO_METHOD_HANDLE handle, mdMethodDef md,
2052 unsigned methodProfilingDataFlags)
2054 _ASSERTE(handle != NULL);
2056 if (m_zapper->m_pOpt->m_onlyOneMethod && (m_zapper->m_pOpt->m_onlyOneMethod != md))
2057 return NOT_COMPILED;
2059 if (GetCompileInfo()->HasCustomAttribute(handle, "System.Runtime.BypassNGenAttribute"))
2060 return NOT_COMPILED;
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())
2066 if (GetCompileInfo()->HasCustomAttribute(handle, "System.Runtime.BypassReadyToRunAttribute"))
2067 return NOT_COMPILED;
2071 // Do we have a profile entry for this method?
2073 if (methodProfilingDataFlags != 0)
2075 // Report the profiling data flags for layout of the EE datastructures
2076 m_pPreloader->SetMethodProfilingFlags(handle, methodProfilingDataFlags);
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.
2081 if ((methodProfilingDataFlags & (1 << ExcludeHotMethodCode)) != 0)
2083 // returning COMPILE_HOT_EXCLUDED excludes this method from the AOT native image
2084 return COMPILE_HOT_EXCLUDED;
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.
2091 if ((methodProfilingDataFlags & (1 << ExcludeColdMethodCode)) != 0)
2093 // returning COMPILE_COLD_EXCLUDED excludes this method from the AOT native image
2094 return COMPILE_COLD_EXCLUDED;
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.
2101 if ((methodProfilingDataFlags & (1 << ReadMethodCode)) == 0)
2103 // returning NOT_COMPILED will defer until later the compilation of this method
2104 return NOT_COMPILED;
2107 else // we are compiling methods for the cold region
2109 // Retrieve any information that we have about a previous compilation attempt of this method
2110 const ProfileDataHashEntry* pEntry = profileDataHashTable.LookupPtr(md);
2112 // When Partial Ngen is specified we will omit the AOT native code for every
2113 // method that does not have profile data
2115 if (pEntry == nullptr && m_zapper->m_pOpt->m_fPartialNGen)
2117 // returning COMPILE_COLD_EXCLUDED excludes this method from the AOT native image
2118 return COMPILE_COLD_EXCLUDED;
2121 if (pEntry != nullptr)
2123 if ((pEntry->status == COMPILE_HOT_EXCLUDED) || (pEntry->status == COMPILE_COLD_EXCLUDED))
2125 // returning COMPILE_HOT_EXCLUDED excludes this method from the AOT native image
2126 return pEntry->status;
2131 // Have we already compiled it?
2132 if (GetCompiledMethod(handle) != NULL)
2133 return ALREADY_COMPILED;
2135 _ASSERTE(m_zapper->m_pOpt->m_compilerFlags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_IL_STUB) || IsNilToken(md) || handle == m_pPreloader->LookupMethodDef(md));
2137 CompileStatus result = NOT_COMPILED;
2139 CORINFO_MODULE_HANDLE module;
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))
2145 module = m_zapper->m_pEEJitInfo->getMethodModule(handle);
2147 ZapInfo zapInfo(this, md, handle, module, methodProfilingDataFlags);
2151 zapInfo.CompileMethod();
2152 result = COMPILE_SUCCEED;
2156 // Continue unwinding if fatal error was hit.
2157 if (FAILED(g_hrFatalError))
2158 ThrowHR(g_hrFatalError);
2160 Exception *ex = GET_EXCEPTION();
2161 HRESULT hrException = ex->GetHR();
2163 CorZapLogLevel level;
2165 #ifdef CROSSGEN_COMPILE
2166 // Warnings should not go to stderr during crossgen
2167 level = CORZAP_LOGLEVEL_WARNING;
2169 level = CORZAP_LOGLEVEL_ERROR;
2171 m_zapper->m_failed = TRUE;
2174 result = COMPILE_FAILED;
2176 #ifdef FEATURE_READYTORUN_COMPILER
2177 // NYI features in R2R - Stop crossgen from spitting unnecessary
2178 // messages to the console
2179 if (IsReadyToRunCompilation())
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.
2185 // We skip the compilation of such methods and we don't want to
2186 // issue a warning or error
2188 if ((hrException == E_NOTIMPL) || (hrException == (HRESULT)IDS_CLASSLOAD_GENERAL))
2190 result = NOT_COMPILED;
2191 level = CORZAP_LOGLEVEL_INFO;
2196 StackSString message;
2197 ex->GetMessage(message);
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)
2203 StackSString logMessage(W("System.IO.FileNotFoundException: "));
2204 logMessage.Append(message);
2205 FileNotFoundError(logMessage.GetUnicode());
2206 level = CORZAP_LOGLEVEL_INFO;
2209 m_zapper->Print(level, W("%s while compiling method %s\n"), message.GetUnicode(), zapInfo.m_currentMethodName.GetUnicode());
2211 if ((result == COMPILE_FAILED) && (m_stats != NULL))
2213 if (!m_zapper->m_pOpt->m_compilerFlags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_IL_STUB))
2214 m_stats->m_failedMethods++;
2216 m_stats->m_failedILStubs++;
2220 EX_END_CATCH(SwallowAllExceptions);
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)
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())
2236 _ASSERTE(partialNGenStressVal <= 100);
2237 DWORD methodPercentageVal = (md % 100) + 1;
2238 if (methodPercentageVal <= partialNGenStressVal)
2243 IfFailThrow(m_pMDImport->GetParentToken(md, &td));
2245 #ifdef FEATURE_COMINTEROP
2247 if (td != mdTypeDefNil)
2249 IfFailThrow(m_pMDImport->GetTypeDefProps(td, NULL, &tkExtends));
2251 mdAssembly tkAssembly;
2252 DWORD dwAssemblyFlags;
2254 IfFailThrow(m_pMDImport->GetAssemblyFromScope(&tkAssembly));
2255 if (TypeFromToken(tkAssembly) == mdtAssembly)
2257 IfFailThrow(m_pMDImport->GetAssemblyProps(tkAssembly,
2258 NULL, NULL, // Public Key
2259 NULL, // Hash Algorithm
2264 if (IsAfContentType_WindowsRuntime(dwAssemblyFlags))
2266 if (TypeFromToken(tkExtends) == mdtTypeRef)
2268 LPCSTR szNameSpace = NULL;
2269 LPCSTR szName = NULL;
2270 IfFailThrow(m_pMDImport->GetNameOfTypeRef(tkExtends, &szNameSpace, &szName));
2272 if (!strcmp(szNameSpace, "System") && !_stricmp((szName), "Attribute"))
2283 static ConfigMethodSet fZapOnly;
2284 fZapOnly.ensureInit(CLRConfig::INTERNAL_ZapOnly);
2286 static ConfigMethodSet fZapExclude;
2287 fZapExclude.ensureInit(CLRConfig::INTERNAL_ZapExclude);
2289 PCCOR_SIGNATURE pvSigBlob;
2292 // Get the name of the current method and its class
2294 IfFailThrow(m_pMDImport->GetNameAndSigOfMethodDef(md, &pvSigBlob, &cbSigBlob, &szMethod));
2296 LPCWSTR wszClass = W("");
2299 if (td != mdTypeDefNil)
2301 LPCSTR szNameSpace = NULL;
2302 LPCSTR szName = NULL;
2304 IfFailThrow(m_pMDImport->GetNameOfTypeDef(td, &szName, &szNameSpace));
2306 const SString nameSpace(SString::Utf8, szNameSpace);
2307 const SString name(SString::Utf8, szName);
2308 sClass.MakeFullNamespacePath(nameSpace, name);
2309 wszClass = sClass.GetUnicode();
2312 MAKE_UTF8PTR_FROMWIDE(szClass, wszClass);
2314 if (!fZapOnly.isEmpty() && !fZapOnly.contains(szMethod, szClass, pvSigBlob))
2316 LOG((LF_ZAP, LL_INFO1000, "Rejecting compilation of method %08x, %s::%s\n", md, szClass, szMethod));
2320 if (fZapExclude.contains(szMethod, szClass, pvSigBlob))
2322 LOG((LF_ZAP, LL_INFO1000, "Rejecting compilation of method %08x, %s::%s\n", md, szClass, szMethod));
2326 LOG((LF_ZAP, LL_INFO1000, "Compiling method %08x, %s::%s\n", md, szClass, szMethod));
2333 BOOL ZapImage::ShouldCompileInstantiatedMethod(CORINFO_METHOD_HANDLE handle)
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())
2341 _ASSERTE(partialNGenStressVal <= 100);
2342 DWORD methodPercentageVal = (m_zapper->m_pEEJitInfo->getMethodHash(handle) % 100) + 1;
2343 if (methodPercentageVal <= partialNGenStressVal)
2350 HRESULT ZapImage::PrintTokenDescription(CorZapLogLevel level, mdToken token)
2354 if (RidFromToken(token) == 0)
2357 LPCSTR szNameSpace = NULL;
2358 LPCSTR szName = NULL;
2360 if (m_pMDImport->IsValidToken(token))
2362 switch (TypeFromToken(token))
2367 IfFailRet(m_pMDImport->GetParentOfMemberRef(token, &parent));
2368 if (RidFromToken(parent) != 0)
2370 PrintTokenDescription(level, parent);
2371 m_zapper->Print(level, W("."));
2373 IfFailRet(m_pMDImport->GetNameAndSigOfMemberRef(token, NULL, NULL, &szName));
2380 IfFailRet(m_pMDImport->GetParentToken(token, &parent));
2381 if (RidFromToken(parent) != 0)
2383 PrintTokenDescription(level, parent);
2384 m_zapper->Print(level, W("."));
2386 IfFailRet(m_pMDImport->GetNameOfMethodDef(token, &szName));
2392 IfFailRet(m_pMDImport->GetNameOfTypeRef(token, &szNameSpace, &szName));
2398 IfFailRet(m_pMDImport->GetNameOfTypeDef(token, &szName, &szNameSpace));
2408 szName = "InvalidToken";
2413 if (szNameSpace != NULL)
2415 const SString nameSpace(SString::Utf8, szNameSpace);
2416 const SString name(SString::Utf8, szName);
2417 fullName.MakeFullNamespacePath(nameSpace, name);
2421 fullName.SetUTF8(szName);
2424 m_zapper->Print(level, W("%s"), fullName.GetUnicode());
2430 HRESULT ZapImage::LocateProfileData()
2432 if (m_zapper->m_pOpt->m_ignoreProfileData)
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
2446 if (m_zapper->m_pOpt->m_compilerFlags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_BBINSTR))
2451 // Don't use IBC data from untrusted assemblies--this allows us to assume that
2452 // the IBC data is not malicious
2454 if (m_zapper->m_pEEJitInfo->canSkipVerification(m_hModule) != CORINFO_VERIFICATION_CAN_SKIP)
2460 // See if there's profile data in the resource section of the PE
2462 m_pRawProfileData = (BYTE*)m_ModuleDecoder.GetWin32Resource(W("PROFILE_DATA"), W("IBC"), &m_cRawProfileData);
2464 if ((m_pRawProfileData != NULL) && (m_cRawProfileData != 0))
2466 m_zapper->Info(W("Found embedded profile resource in %s.\n"), m_pModuleFileName);
2470 static ConfigDWORD g_UseIBCFile;
2471 if (g_UseIBCFile.val(CLRConfig::EXTERNAL_UseIBCFile) != 1)
2475 // Couldn't find profile resource--let's see if there's an ibc file to use instead
2478 SString path(m_pModuleFileName);
2480 SString::Iterator dot = path.End();
2481 if (path.FindBack(dot, '.'))
2483 SString slName(SString::Literal, "ibc");
2484 path.Replace(dot+1, path.End() - (dot+1), slName);
2486 HandleHolder hFile = WszCreateFile(path.GetUnicode(),
2491 FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,
2493 if (hFile != INVALID_HANDLE_VALUE)
2495 HandleHolder hMapFile = WszCreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
2496 DWORD dwFileLen = SafeGetFileSize(hFile, 0);
2497 if (dwFileLen != INVALID_FILE_SIZE)
2499 if (hMapFile == NULL)
2501 m_zapper->Warning(W("Found profile data file %s, but could not open it"), path.GetUnicode());
2505 m_zapper->Info(W("Found ibc file %s.\n"), path.GetUnicode());
2507 m_profileDataFile = (BYTE*) MapViewOfFile(hMapFile, FILE_MAP_READ, 0, 0, 0);
2509 m_pRawProfileData = m_profileDataFile;
2510 m_cRawProfileData = dwFileLen;
2520 bool ZapImage::CanConvertIbcData()
2522 static ConfigDWORD g_iConvertIbcData;
2523 DWORD val = g_iConvertIbcData.val(CLRConfig::UNSUPPORTED_ConvertIbcData);
2527 HRESULT ZapImage::parseProfileData()
2529 if (m_pRawProfileData == NULL)
2534 ProfileReader profileReader(m_pRawProfileData, m_cRawProfileData);
2536 CORBBTPROF_FILE_HEADER *fileHeader;
2538 READ(fileHeader, CORBBTPROF_FILE_HEADER);
2539 if (fileHeader->HeaderSize < sizeof(CORBBTPROF_FILE_HEADER))
2541 _ASSERTE(!"HeaderSize is too small");
2545 // Read any extra header data. It will be needed for V3 files.
2547 DWORD extraHeaderDataSize = fileHeader->HeaderSize - sizeof(CORBBTPROF_FILE_HEADER);
2548 void *extraHeaderData = profileReader.Read(extraHeaderDataSize);
2550 bool convertFromV1 = false;
2551 bool minified = false;
2553 if (fileHeader->Magic != CORBBTPROF_MAGIC)
2555 _ASSERTE(!"ibcHeader contains bad values");
2559 // CoreCLR should never be presented with V1 IBC data.
2560 if (fileHeader->Version == CORBBTPROF_V3_VERSION)
2562 CORBBTPROF_FILE_OPTIONAL_HEADER *optionalHeader =
2563 (CORBBTPROF_FILE_OPTIONAL_HEADER *)extraHeaderData;
2565 if (!optionalHeader ||
2566 !CONTAINS_FIELD(optionalHeader, extraHeaderDataSize, Size) ||
2567 (optionalHeader->Size > extraHeaderDataSize))
2569 m_zapper->Info(W("Optional header missing or corrupt."));
2573 if (CONTAINS_FIELD(optionalHeader, optionalHeader->Size, FileFlags))
2575 minified = !!(optionalHeader->FileFlags & CORBBTPROF_FILE_FLAG_MINIFIED);
2577 if (!m_zapper->m_pOpt->m_fPartialNGenSet)
2579 m_zapper->m_pOpt->m_fPartialNGen = !!(optionalHeader->FileFlags & CORBBTPROF_FILE_FLAG_PARTIAL_NGEN);
2583 else if (fileHeader->Version != CORBBTPROF_V2_VERSION)
2585 m_zapper->Info(W("Discarding profile data with unknown version."));
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;
2594 CORBBTPROF_SECTION_TABLE_HEADER *sectionHeader;
2595 READ(sectionHeader, CORBBTPROF_SECTION_TABLE_HEADER);
2598 // Parse the section table
2601 for (ULONG i = 0; i < sectionHeader->NumEntries; i++)
2603 CORBBTPROF_SECTION_TABLE_ENTRY *entry;
2604 READ(entry,CORBBTPROF_SECTION_TABLE_ENTRY);
2606 SectionFormat format = sectionHeader->Entries[i].FormatID;
2607 _ASSERTE(format >= 0);
2615 if (format < LastTokenFlagSection)
2617 format = (SectionFormat) (format + 1);
2621 _ASSERTE(format < SectionFormatCount);
2623 if (format < SectionFormatCount)
2625 BYTE *start = m_pRawProfileData + sectionHeader->Entries[i].Data.Offset;
2626 BYTE *end = start + sectionHeader->Entries[i].Data.Size;
2628 if ((start > m_pRawProfileData) &&
2629 (end < m_pRawProfileData + m_cRawProfileData) &&
2632 _ASSERTE(m_profileDataSections[format].pData == 0);
2633 _ASSERTE(m_profileDataSections[format].dataSize == 0);
2635 m_profileDataSections[format].pData = start;
2636 m_profileDataSections[format].dataSize = (DWORD) (end - start);
2640 _ASSERTE(!"Invalid profile section offset or size");
2650 hr = convertProfileDataFromV1();
2658 hr = RehydrateProfileData();
2667 // For those sections that are collections of tokens, further parse that format to get
2668 // the token pointer and number of tokens
2671 for (int format = FirstTokenFlagSection; format < SectionFormatCount; format++)
2673 if (m_profileDataSections[format].pData)
2675 SEEK(((ULONG) (m_profileDataSections[format].pData - m_pRawProfileData)));
2677 CORBBTPROF_TOKEN_LIST_SECTION_HEADER *header;
2678 READ(header, CORBBTPROF_TOKEN_LIST_SECTION_HEADER);
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);
2684 if (dataSize == expectedSize)
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;
2692 _ASSERTE(!"Invalid CORBBTPROF_TOKEN_LIST_SECTION_HEADER header");
2699 ZapImage::ProfileDataSection * DataSection_ScenarioInfo = & m_profileDataSections[ScenarioInfo];
2700 if (DataSection_ScenarioInfo->pData != NULL)
2702 CORBBTPROF_SCENARIO_INFO_SECTION_HEADER * header = (CORBBTPROF_SCENARIO_INFO_SECTION_HEADER *) DataSection_ScenarioInfo->pData;
2703 m_profileDataNumRuns = header->TotalNumRuns;
2710 HRESULT ZapImage::convertProfileDataFromV1()
2712 if (m_pRawProfileData == NULL)
2718 // For those sections that are collections of tokens, further parse that format to get
2719 // the token pointer and number of tokens
2722 ProfileReader profileReader(m_pRawProfileData, m_cRawProfileData);
2724 for (SectionFormat format = FirstTokenFlagSection; format < SectionFormatCount; format = (SectionFormat) (format + 1))
2726 if (m_profileDataSections[format].pData)
2728 SEEK(((ULONG) (m_profileDataSections[format].pData - m_pRawProfileData)));
2730 CORBBTPROF_TOKEN_LIST_SECTION_HEADER *header;
2731 READ(header, CORBBTPROF_TOKEN_LIST_SECTION_HEADER);
2733 DWORD tableSize = header->NumTokens;
2737 m_profileDataSections[format].tableSize = 0;
2738 m_profileDataSections[format].pTable = NULL;
2742 DWORD dataSize = (m_profileDataSections[format].dataSize - sizeof(CORBBTPROF_TOKEN_LIST_SECTION_HEADER));
2743 DWORD expectedSize = tableSize * sizeof (CORBBTPROF_TOKEN_LIST_ENTRY_V1);
2745 if (dataSize == expectedSize)
2747 DWORD newDataSize = tableSize * sizeof (CORBBTPROF_TOKEN_INFO);
2749 if (newDataSize < dataSize)
2752 BYTE * startOfTable = new (GetHeap()) BYTE[newDataSize];
2754 CORBBTPROF_TOKEN_LIST_ENTRY_V1 * pOldEntry;
2755 CORBBTPROF_TOKEN_INFO * pNewEntry;
2757 pOldEntry = (CORBBTPROF_TOKEN_LIST_ENTRY_V1 *) (m_profileDataSections[format].pData + sizeof(CORBBTPROF_TOKEN_LIST_SECTION_HEADER));
2758 pNewEntry = (CORBBTPROF_TOKEN_INFO *) startOfTable;
2760 for (DWORD i=0; i<tableSize; i++)
2762 pNewEntry->token = pOldEntry->token;
2763 pNewEntry->flags = pOldEntry->flags;
2764 pNewEntry->scenarios = 1;
2769 m_profileDataSections[format].tableSize = tableSize;
2770 m_profileDataSections[format].pTable = (CORBBTPROF_TOKEN_INFO *) startOfTable;
2774 _ASSERTE(!"Invalid CORBBTPROF_TOKEN_LIST_SECTION_HEADER header");
2780 _ASSERTE(m_profileDataSections[ScenarioInfo].pData == 0);
2781 _ASSERTE(m_profileDataSections[ScenarioInfo].dataSize == 0);
2784 // Convert the MethodBlockCounts format from V1 to V2
2786 CORBBTPROF_METHOD_BLOCK_COUNTS_SECTION_HEADER_V1 * mbcSectionHeader = NULL;
2787 if (m_profileDataSections[MethodBlockCounts].pData)
2790 // Compute the size of the method block count stream
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;
2798 mbcSectionHeader = (CORBBTPROF_METHOD_BLOCK_COUNTS_SECTION_HEADER_V1 *) srcPtr;
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);
2804 if (totalSizeRead > maxSizeToRead)
2809 for (DWORD i=0; (i < mbcSectionHeader->NumMethods); i++)
2811 CORBBTPROF_METHOD_HEADER_V1* methodEntry = (CORBBTPROF_METHOD_HEADER_V1 *) srcPtr;
2813 DWORD sizeWrite = 0;
2815 sizeRead += methodEntry->HeaderSize;
2816 sizeRead += methodEntry->Size;
2817 sizeWrite += sizeof(CORBBTPROF_METHOD_HEADER);
2818 sizeWrite += methodEntry->Size;
2820 totalSizeRead += sizeRead;
2821 totalSizeNeeded += sizeWrite;
2823 if (totalSizeRead > maxSizeToRead)
2830 assert(totalSizeRead == maxSizeToRead);
2833 srcPtr = m_profileDataSections[MethodBlockCounts].pData;
2835 BYTE * newMethodData = new (GetHeap()) BYTE[totalSizeNeeded];
2837 dstPtr = newMethodData;
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);
2843 for (DWORD i=0; (i < mbcSectionHeader->NumMethods); i++)
2845 CORBBTPROF_METHOD_HEADER_V1 * methodEntryV1 = (CORBBTPROF_METHOD_HEADER_V1 *) srcPtr;
2846 CORBBTPROF_METHOD_HEADER * methodEntry = (CORBBTPROF_METHOD_HEADER *) dstPtr;
2848 DWORD sizeWrite = 0;
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);
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));
2862 methodEntry->size = sizeWrite;
2863 methodEntry->cDetail = 0;
2865 dstPtr += sizeWrite;
2868 m_profileDataSections[MethodBlockCounts].pData = newMethodData;
2869 m_profileDataSections[MethodBlockCounts].dataSize = totalSizeNeeded;
2873 // Allocate the scenario info section
2876 DWORD sizeNeeded = sizeof(CORBBTPROF_SCENARIO_INFO_SECTION_HEADER) + sizeof(CORBBTPROF_SCENARIO_HEADER);
2877 BYTE * newData = new (GetHeap()) BYTE[sizeNeeded];
2878 BYTE * dstPtr = newData;
2880 CORBBTPROF_SCENARIO_INFO_SECTION_HEADER *siHeader = (CORBBTPROF_SCENARIO_INFO_SECTION_HEADER *) dstPtr;
2882 if (mbcSectionHeader != NULL)
2883 siHeader->TotalNumRuns = mbcSectionHeader->NumRuns;
2885 siHeader->TotalNumRuns = 1;
2887 siHeader->NumScenarios = 1;
2889 dstPtr += sizeof(CORBBTPROF_SCENARIO_INFO_SECTION_HEADER);
2892 CORBBTPROF_SCENARIO_HEADER *sHeader = (CORBBTPROF_SCENARIO_HEADER *) dstPtr;
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;
2900 sHeader->size = sHeader->Size();
2902 dstPtr += sizeof(CORBBTPROF_SCENARIO_HEADER);
2904 m_profileDataSections[ScenarioInfo].pData = newData;
2905 m_profileDataSections[ScenarioInfo].dataSize = sizeNeeded;
2909 // Convert the BlobStream format from V1 to V2
2911 if (m_profileDataSections[BlobStream].dataSize > 0)
2914 // Compute the size of the blob stream
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;
2926 CORBBTPROF_BLOB_ENTRY_V1* blobEntry = (CORBBTPROF_BLOB_ENTRY_V1 *) srcPtr;
2927 DWORD sizeWrite = 0;
2930 if ((blobEntry->blobType >= MetadataStringPool) && (blobEntry->blobType <= MetadataUserStringPool))
2932 sizeWrite += sizeof(CORBBTPROF_BLOB_POOL_ENTRY);
2933 sizeWrite += blobEntry->cBuffer;
2934 sizeRead += sizeof(CORBBTPROF_BLOB_ENTRY_V1);
2935 sizeRead += blobEntry->cBuffer;
2937 else if ((blobEntry->blobType >= ParamTypeSpec) && (blobEntry->blobType <= ParamMethodSpec))
2939 sizeWrite += sizeof(CORBBTPROF_BLOB_PARAM_SIG_ENTRY);
2940 sizeWrite += blobEntry->cBuffer;
2941 if (blobEntry->blobType == ParamMethodSpec)
2943 sizeWrite -= 1; // Adjust for
2945 sizeRead += sizeof(CORBBTPROF_BLOB_ENTRY_V1);
2946 sizeRead += blobEntry->cBuffer;
2948 else if (blobEntry->blobType == EndOfBlobStream)
2950 sizeWrite += sizeof(CORBBTPROF_BLOB_ENTRY);
2951 sizeRead += sizeof(CORBBTPROF_BLOB_ENTRY_V1);
2959 totalSizeNeeded += sizeWrite;
2960 totalSizeRead += sizeRead;
2962 if (sizeRead > maxSizeToRead)
2970 assert(totalSizeRead == maxSizeToRead);
2973 srcPtr = m_profileDataSections[BlobStream].pData;
2975 BYTE * newBlobData = new (GetHeap()) BYTE[totalSizeNeeded];
2977 dstPtr = newBlobData;
2982 CORBBTPROF_BLOB_ENTRY_V1* blobEntryV1 = (CORBBTPROF_BLOB_ENTRY_V1 *) srcPtr;
2983 DWORD sizeWrite = 0;
2986 if ((blobEntryV1->blobType >= MetadataStringPool) && (blobEntryV1->blobType <= MetadataUserStringPool))
2988 CORBBTPROF_BLOB_POOL_ENTRY* blobPoolEntry = (CORBBTPROF_BLOB_POOL_ENTRY*) dstPtr;
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);
2995 sizeWrite += sizeof(CORBBTPROF_BLOB_POOL_ENTRY);
2996 sizeWrite += blobEntryV1->cBuffer;
2997 sizeRead += sizeof(CORBBTPROF_BLOB_ENTRY_V1);
2998 sizeRead += blobEntryV1->cBuffer;
3000 else if ((blobEntryV1->blobType >= ParamTypeSpec) && (blobEntryV1->blobType <= ParamMethodSpec))
3002 CORBBTPROF_BLOB_PARAM_SIG_ENTRY* blobSigEntry = (CORBBTPROF_BLOB_PARAM_SIG_ENTRY*) dstPtr;
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;
3009 if (blobEntryV1->blobType == ParamMethodSpec)
3011 // Adjust cSig and blob.size
3012 blobSigEntry->cSig--;
3013 blobSigEntry->blob.size--;
3015 memcpy(blobSigEntry->sig, blobEntryV1->pBuffer, blobSigEntry->cSig);
3017 sizeWrite += sizeof(CORBBTPROF_BLOB_PARAM_SIG_ENTRY);
3018 sizeWrite += blobSigEntry->cSig;
3019 sizeRead += sizeof(CORBBTPROF_BLOB_ENTRY_V1);
3020 sizeRead += blobEntryV1->cBuffer;
3022 else if (blobEntryV1->blobType == EndOfBlobStream)
3024 CORBBTPROF_BLOB_ENTRY* blobEntry = (CORBBTPROF_BLOB_ENTRY*) dstPtr;
3026 blobEntry->type = blobEntryV1->blobType;
3027 blobEntry->size = sizeof(CORBBTPROF_BLOB_ENTRY);
3029 sizeWrite += sizeof(CORBBTPROF_BLOB_ENTRY);
3030 sizeRead += sizeof(CORBBTPROF_BLOB_ENTRY_V1);
3038 dstPtr += sizeWrite;
3041 m_profileDataSections[BlobStream].pData = newBlobData;
3042 m_profileDataSections[BlobStream].dataSize = totalSizeNeeded;
3046 m_profileDataSections[BlobStream].pData = NULL;
3047 m_profileDataSections[BlobStream].dataSize = 0;
3053 void ZapImage::RehydrateBasicBlockSection()
3055 ProfileDataSection §ion = m_profileDataSections[MethodBlockCounts];
3061 ProfileReader reader(section.pData, section.dataSize);
3063 m_profileDataNumRuns = reader.Read<unsigned int>();
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
3068 unsigned int blockCountHint = reader.Read<unsigned int>();
3070 unsigned int numMethods = reader.Read<unsigned int>();
3072 unsigned int expectedLength =
3073 sizeof(CORBBTPROF_METHOD_BLOCK_COUNTS_SECTION_HEADER) +
3074 sizeof(CORBBTPROF_METHOD_HEADER) * numMethods +
3075 sizeof(CORBBTPROF_BLOCK_DATA) * blockCountHint;
3077 BinaryWriter writer(expectedLength, GetHeap());
3079 writer.Write(numMethods);
3081 mdToken lastMethodToken = 0x06000000;
3083 CORBBTPROF_METHOD_HEADER methodHeader;
3084 methodHeader.cDetail = 0;
3085 methodHeader.method.ILSize = 0;
3087 for (unsigned int i = 0; i < numMethods; ++i)
3089 // Translate the method header
3090 unsigned int size = reader.Read7BitEncodedInt();
3091 unsigned int startPosition = reader.GetCurrentPos();
3093 mdToken token = reader.ReadTokenWithMemory(lastMethodToken);
3094 unsigned int ilSize = reader.Read7BitEncodedInt();
3095 unsigned int firstBlockHitCount = reader.Read7BitEncodedInt();
3097 unsigned int numOtherBlocks = reader.Read7BitEncodedInt();
3099 methodHeader.method.cBlock = 1 + numOtherBlocks;
3100 methodHeader.method.token = token;
3101 methodHeader.method.ILSize = ilSize;
3102 methodHeader.size = (DWORD)methodHeader.Size();
3104 writer.Write(methodHeader);
3106 CORBBTPROF_BLOCK_DATA blockData;
3108 // The first block is handled specially.
3109 blockData.ILOffset = 0;
3110 blockData.ExecutionCount = firstBlockHitCount;
3112 writer.Write(blockData);
3114 // Translate the rest of the basic blocks
3115 for (unsigned int j = 0; j < numOtherBlocks; ++j)
3117 blockData.ILOffset = reader.Read7BitEncodedInt();
3118 blockData.ExecutionCount = reader.Read7BitEncodedInt();
3120 writer.Write(blockData);
3123 if (!reader.Seek(startPosition + size))
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);
3133 section.pData = writer.GetBuffer();
3134 section.dataSize = writer.GetWrittenSize();
3137 void ZapImage::RehydrateTokenSection(int sectionFormat, unsigned int flagTable[255])
3139 ProfileDataSection §ion = m_profileDataSections[sectionFormat];
3140 ProfileReader reader(section.pData, section.dataSize);
3142 unsigned int numTokens = reader.Read<unsigned int>();
3144 unsigned int dataLength = sizeof(unsigned int) +
3145 numTokens * sizeof(CORBBTPROF_TOKEN_INFO);
3146 BinaryWriter writer(dataLength, GetHeap());
3148 writer.Write(numTokens);
3150 mdToken lastToken = (sectionFormat - FirstTokenFlagSection) << 24;
3152 CORBBTPROF_TOKEN_INFO tokenInfo;
3153 tokenInfo.scenarios = 1;
3155 for (unsigned int i = 0; i < numTokens; ++i)
3157 tokenInfo.token = reader.ReadTokenWithMemory(lastToken);
3158 tokenInfo.flags = reader.ReadFlagWithLookup(flagTable);
3160 writer.Write(tokenInfo);
3163 _ASSERTE(writer.GetWrittenSize() == dataLength);
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;
3171 void ZapImage::RehydrateBlobStream()
3173 ProfileDataSection §ion = m_profileDataSections[BlobStream];
3175 ProfileReader reader(section.pData, section.dataSize);
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());
3182 mdToken LastBlobToken = 0;
3183 mdToken LastAssemblyToken = 0x23000000;
3184 mdToken LastExternalTypeToken = 0x62000000;
3185 mdToken LastExternalNamespaceToken = 0x61000000;
3186 mdToken LastExternalSignatureToken = 0x63000000;
3191 // Read the blob header.
3193 unsigned int sizeToRead = reader.Read7BitEncodedInt();
3194 unsigned int startPositionRead = reader.GetCurrentPos();
3196 blobType = reader.Read7BitEncodedInt();
3197 mdToken token = reader.ReadTokenWithMemory(LastBlobToken);
3199 // Write out the blob header.
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
3206 unsigned int startPositionWrite = writer.GetWrittenSize();
3209 writer.Write(blobType);
3210 writer.Write(token);
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.
3217 if (blobType == ExternalTypeDef)
3219 writer.Write(reader.ReadTokenWithMemory(LastAssemblyToken));
3220 writer.Write(reader.ReadTokenWithMemory(LastExternalTypeToken));
3221 writer.Write(reader.ReadTokenWithMemory(LastExternalNamespaceToken));
3223 else if (blobType == ExternalMethodDef)
3225 writer.Write(reader.ReadTokenWithMemory(LastExternalTypeToken));
3226 writer.Write(reader.ReadTokenWithMemory(LastExternalSignatureToken));
3229 if ((blobType >= MetadataStringPool) && (blobType < IllegalBlob))
3231 // This blob is of known type and ends with data.
3232 unsigned int dataLength = reader.Read7BitEncodedInt();
3233 char *data = (char *)reader.Read(dataLength);
3240 writer.Write(dataLength);
3241 writer.Write(data, dataLength);
3244 // Write the size for this blob.
3246 writer.WriteAt(startPositionWrite,
3247 writer.GetWrittenSize() - startPositionWrite);
3249 // Move to the next blob.
3251 if (!reader.Seek(startPositionRead + sizeToRead))
3256 while (blobType != EndOfBlobStream);
3258 section.pData = writer.GetBuffer();
3259 section.dataSize = writer.GetWrittenSize();
3262 HRESULT ZapImage::RehydrateProfileData()
3265 unsigned int flagTable[255];
3266 memset(flagTable, 0xFF, sizeof(flagTable));
3270 RehydrateBasicBlockSection();
3271 RehydrateBlobStream();
3272 for (int format = FirstTokenFlagSection;
3273 format < SectionFormatCount;
3276 if (m_profileDataSections[format].pData)
3278 RehydrateTokenSection(format, flagTable);
3282 EX_CATCH_HRESULT_NO_ERRORINFO(hr);
3287 HRESULT ZapImage::hashMethodBlockCounts()
3289 ProfileDataSection * DataSection_MethodBlockCounts = & m_profileDataSections[MethodBlockCounts];
3291 if (!DataSection_MethodBlockCounts->pData)
3296 ProfileReader profileReader(DataSection_MethodBlockCounts->pData, DataSection_MethodBlockCounts->dataSize);
3298 CORBBTPROF_METHOD_BLOCK_COUNTS_SECTION_HEADER *mbcHeader;
3299 READ(mbcHeader,CORBBTPROF_METHOD_BLOCK_COUNTS_SECTION_HEADER);
3301 for (DWORD i = 0; i < mbcHeader->NumMethods; i++)
3303 ProfileDataHashEntry newEntry;
3304 newEntry.pos = profileReader.GetCurrentPos();
3306 CORBBTPROF_METHOD_HEADER *methodHeader;
3307 READ(methodHeader,CORBBTPROF_METHOD_HEADER);
3308 newEntry.md = methodHeader->method.token;
3309 newEntry.size = methodHeader->size;
3311 newEntry.status = NOT_COMPILED;
3313 // Add the new entry to the table
3314 profileDataHashTable.Add(newEntry);
3316 // Skip the profileData so we can read the next method.
3318 READ_SIZE(profileData, void, (methodHeader->size - sizeof(CORBBTPROF_METHOD_HEADER)));
3324 void ZapImage::hashBBUpdateFlagsAndCompileResult(mdToken token, unsigned methodProfilingDataFlags, ZapImage::CompileStatus compileResult)
3326 // SHash only supports replacing an entry so we setup our newEntry and then perform a lookup
3328 ProfileDataHashEntry newEntry;
3329 newEntry.md = token;
3330 newEntry.flags = methodProfilingDataFlags;
3331 newEntry.status = compileResult;
3333 const ProfileDataHashEntry* pEntry = profileDataHashTable.LookupPtr(token);
3334 if (pEntry != nullptr)
3336 assert(pEntry->md == newEntry.md);
3337 assert(pEntry->flags == 0); // the flags should not be set at this point.
3339 // Copy and keep the two fleids that were previously set
3340 newEntry.size = pEntry->size;
3341 newEntry.pos = pEntry->pos;
3343 else // We have a method that doesn't have basic block counts
3348 profileDataHashTable.AddOrReplace(newEntry);
3351 void ZapImage::LoadProfileData()
3353 HRESULT hr = E_FAIL;
3355 m_fHaveProfileData = false;
3356 m_pRawProfileData = NULL;
3357 m_cRawProfileData = 0;
3361 hr = LocateProfileData();
3365 hr = parseProfileData();
3368 hr = hashMethodBlockCounts();
3376 EX_END_CATCH(SwallowAllExceptions);
3380 m_fHaveProfileData = false;
3381 m_pRawProfileData = NULL;
3382 m_cRawProfileData = 0;
3386 m_zapper->Warning(W("Warning: Invalid profile data was ignored for %s\n"), m_pModuleFileName);
3390 #ifdef CROSSGEN_COMPILE
3391 if (m_zapper->m_pOpt->m_fPartialNGen && (m_pRawProfileData == NULL || m_cRawProfileData == 0))
3393 ThrowHR(CLR_E_CROSSGEN_NO_IBC_DATA_FOUND);
3398 // Initializes our form of the profile data stored in the assembly.
3400 CorProfileData * ZapImage::NewProfileData()
3402 this->m_pCorProfileData = new CorProfileData(&m_profileDataSections[0]);
3404 return this->m_pCorProfileData;
3407 // Returns the profile data stored in the assembly.
3409 CorProfileData * ZapImage::GetProfileData()
3411 _ASSERTE(this->m_pCorProfileData != NULL);
3413 return this->m_pCorProfileData;
3416 CorProfileData::CorProfileData(void * rawProfileData)
3418 ZapImage::ProfileDataSection * profileData = (ZapImage::ProfileDataSection *) rawProfileData;
3420 for (DWORD format = 0; format < SectionFormatCount; format++)
3422 this->profilingTokenFlagsData[format].count = profileData[format].tableSize;
3423 this->profilingTokenFlagsData[format].data = profileData[format].pTable;
3426 this->blobStream = (CORBBTPROF_BLOB_ENTRY *) profileData[BlobStream].pData;
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.
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.
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*/)
3444 CorInfoIndirectCallReason reason;
3445 if (pReason == NULL)
3447 *pReason = CORINFO_INDIRECT_CALL_UNKNOWN;
3449 // The caller should have checked that the method is in current loader module
3450 _ASSERTE(m_hModule == m_zapper->m_pEECompileInfo->GetLoaderModuleForEmbeddableMethod(targetFtn));
3452 // No direct calls at all under some circumstances
3454 if (m_zapper->m_pOpt->m_compilerFlags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_PROF_ENTERLEAVE)
3455 && !m_pPreloader->IsDynamicMethod(callerFtn))
3457 *pReason = CORINFO_INDIRECT_CALL_PROFILING;
3458 goto CALL_VIA_ENTRY_POINT;
3461 // Does the methods's class have a cctor, etc?
3463 if (!m_pPreloader->CanSkipMethodPreparation(callerFtn, targetFtn, pReason, accessFlags))
3464 goto CALL_VIA_ENTRY_POINT;
3466 ZapMethodHeader * pMethod;
3467 pMethod = GetCompiledMethod(targetFtn);
3469 // If we have not compiled the method then we can't call direct
3471 if (pMethod == NULL)
3473 *pReason = CORINFO_INDIRECT_CALL_NO_CODE;
3474 goto CALL_VIA_ENTRY_POINT;
3477 // Does the method have fixups?
3479 if (pMethod->HasFixups() != NULL)
3481 *pReason = CORINFO_INDIRECT_CALL_FIXUPS;
3482 goto CALL_VIA_ENTRY_POINT;
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));
3494 CALL_VIA_ENTRY_POINT:
3497 methodName = m_zapper->m_pEEJitInfo->getMethodName(targetFtn, &clsName);
3498 LOG((LF_ZAP, LL_INFO10000, "getIntraModuleDirectCallAddr: Via EntryPoint %s::%s\n",
3499 clsName, methodName));
3509 void ZapImage::WriteReloc(PVOID pSrc, int offset, ZapNode * pTarget, int targetOffset, ZapRelocationType type)
3511 _ASSERTE(!IsWritingRelocs());
3513 _ASSERTE(m_pBaseRelocs != NULL);
3514 m_pBaseRelocs->WriteReloc(pSrc, offset, pTarget, targetOffset, type);
3517 ZapImage * ZapImage::GetZapImage()
3522 void ZapImage::FileNotFoundError(LPCWSTR pszMessage)
3524 SString message(pszMessage);
3526 for (COUNT_T i = 0; i < fileNotFoundErrorsTable.GetCount(); i++)
3528 // Check to see if same error has already been displayed for this ngen operation
3529 if (message.Equals(fileNotFoundErrorsTable[i]))
3533 CorZapLogLevel level;
3535 #ifdef CROSSGEN_COMPILE
3536 // Warnings should not go to stderr during crossgen
3537 level = CORZAP_LOGLEVEL_WARNING;
3539 level = CORZAP_LOGLEVEL_ERROR;
3542 m_zapper->Print(level, W("Warning: %s.\n"), pszMessage);
3544 fileNotFoundErrorsTable.Append(message);
3547 void ZapImage::Error(mdToken token, HRESULT hr, UINT resID, LPCWSTR message)
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);
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
3560 if ((TypeFromToken(token) == mdtMethodDef) && IsVTableGapMethod(token))
3565 CorZapLogLevel level = CORZAP_LOGLEVEL_ERROR;
3567 // Some warnings are demoted to informational level
3568 if (resID == IDS_EE_SIMD_NGEN_DISALLOWED)
3570 // Supress printing of "Target-dependent SIMD vector types may not be used with ngen."
3571 level = CORZAP_LOGLEVEL_INFO;
3574 if (resID == IDS_EE_HWINTRINSIC_NGEN_DISALLOWED)
3576 // Supress printing of "Hardware intrinsics may not be used with ngen."
3577 level = CORZAP_LOGLEVEL_INFO;
3580 #ifdef CROSSGEN_COMPILE
3581 if ((resID == IDS_IBC_MISSING_EXTERNAL_TYPE) ||
3582 (resID == IDS_IBC_MISSING_EXTERNAL_METHOD))
3584 // Suppress printing IBC related warnings except in verbose mode.
3585 if (m_zapper->m_pOpt->m_ignoreErrors && !m_zapper->m_pOpt->m_verbose)
3588 // Supress printing of "The generic type/method specified by the IBC data is not available to this assembly"
3589 level = CORZAP_LOGLEVEL_INFO;
3593 if (m_zapper->m_pOpt->m_ignoreErrors)
3595 #ifdef CROSSGEN_COMPILE
3596 // Warnings should not go to stderr during crossgen
3597 if (level == CORZAP_LOGLEVEL_ERROR)
3599 level = CORZAP_LOGLEVEL_WARNING;
3602 m_zapper->Print(level, W("Warning: "));
3606 m_zapper->Print(level, W("Error: "));
3609 if (message != NULL)
3610 m_zapper->Print(level, W("%s"), message);
3612 m_zapper->PrintErrorMessage(level, hr);
3614 m_zapper->Print(level, W(" while resolving 0x%x - "), token);
3615 PrintTokenDescription(level, token);
3616 m_zapper->Print(level, W(".\n"));
3618 if (m_zapper->m_pOpt->m_ignoreErrors)
3624 ZapNode * ZapImage::GetInnerPtr(ZapNode * pNode, SSIZE_T offset)
3626 return m_pInnerPtrs->Get(pNode, offset);
3629 ZapNode * ZapImage::GetHelperThunk(CorInfoHelpFunc ftnNum)
3631 ZapNode * pHelperThunk = m_pHelperThunks[ftnNum];
3633 if (pHelperThunk == NULL)
3635 pHelperThunk = new (GetHeap()) ZapHelperThunk(ftnNum);
3637 pHelperThunk = GetInnerPtr(pHelperThunk, THUMB_CODE);
3639 m_pHelperThunks[ftnNum] = pHelperThunk;
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);
3649 return pHelperThunk;
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
3658 void ZapImage::ComputeClassLayoutOrder()
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:
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
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.
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)
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()];
3684 unsigned classOrder = 0;
3685 for (COUNT_T i = m_iUntrainedMethod; i < m_MethodCompilationOrder.GetCount(); i++)
3687 unsigned classQueueNext = 0;
3688 unsigned classQueueEnd = 0;
3689 COUNT_T methodIndex = 0;
3692 // Find an unprocessed method to seed the next breadth-first traversal.
3695 ZapMethodHeader * pMethod = m_MethodCompilationOrder[i];
3696 const ClassLayoutOrderEntry * pEntry = m_ClassLayoutOrder.LookupPtr(pMethod->m_classHandle);
3699 if ((pEntry->m_order & UNSEEN_CLASS_FLAG) == 0)
3705 // Enqueue the method's class and start the traversal.
3708 classQueue[classQueueEnd++] = pMethod->m_classHandle;
3709 ((ClassLayoutOrderEntry *)pEntry)->m_order &= ~UNSEEN_CLASS_FLAG;
3711 while (classQueueNext < classQueueEnd)
3714 // Dequeue a class and pull out the index of its first method
3717 CORINFO_CLASS_HANDLE dequeuedClassHandle = classQueue[classQueueNext++];
3718 _ASSERTE(dequeuedClassHandle != NULL);
3720 pEntry = m_ClassLayoutOrder.LookupPtr(dequeuedClassHandle);
3722 _ASSERTE((pEntry->m_order & UNSEEN_CLASS_FLAG) == 0);
3723 _ASSERTE((pEntry->m_order & METHOD_INDEX_FLAG) != 0);
3725 methodIndex = pEntry->m_order & ~METHOD_INDEX_FLAG;
3726 _ASSERTE(methodIndex < m_MethodCompilationOrder.GetCount());
3729 // Set the real layout order of the class, and examine its unprofiled methods
3732 ((ClassLayoutOrderEntry *)pEntry)->m_order = ++classOrder;
3734 pMethod = m_MethodCompilationOrder[methodIndex];
3735 _ASSERTE(pMethod->m_classHandle == dequeuedClassHandle);
3737 while (pMethod->m_classHandle == dequeuedClassHandle)
3741 // For each unprofiled method, find target classes and enqueue any that haven't been seen
3744 ZapMethodHeader::PartialTargetMethodIterator it(pMethod);
3746 CORINFO_METHOD_HANDLE targetMethodHandle;
3747 while (it.GetNext(&targetMethodHandle))
3749 CORINFO_CLASS_HANDLE targetClassHandle = GetJitInfo()->getMethodClass(targetMethodHandle);
3750 if (targetClassHandle != pMethod->m_classHandle)
3752 pEntry = m_ClassLayoutOrder.LookupPtr(targetClassHandle);
3754 if (pEntry && (pEntry->m_order & UNSEEN_CLASS_FLAG) != 0)
3756 _ASSERTE(classQueueEnd < m_ClassLayoutOrder.GetCount());
3757 classQueue[classQueueEnd++] = targetClassHandle;
3759 ((ClassLayoutOrderEntry *)pEntry)->m_order &= ~UNSEEN_CLASS_FLAG;
3764 if (++methodIndex == m_MethodCompilationOrder.GetCount())
3769 pMethod = m_MethodCompilationOrder[methodIndex];
3774 for (COUNT_T i = m_iUntrainedMethod; i < m_MethodCompilationOrder.GetCount(); i++)
3776 ZapMethodHeader * pMethod = m_MethodCompilationOrder[i];
3777 pMethod->m_cachedLayoutOrder = LookupClassLayoutOrder(pMethod->m_classHandle);
3780 m_fHasClassLayoutOrder = true;
3782 delete [] classQueue;
3785 static int __cdecl LayoutOrderCmp(const void* a_, const void* b_)
3787 ZapMethodHeader * a = *((ZapMethodHeader**)a_);
3788 ZapMethodHeader * b = *((ZapMethodHeader**)b_);
3790 int layoutDiff = a->GetCachedLayoutOrder() - b->GetCachedLayoutOrder();
3791 if (layoutDiff != 0)
3794 // Use compilation order as secondary key to get predictable ordering within the bucket
3795 return a->GetCompilationOrder() - b->GetCompilationOrder();
3798 void ZapImage::SortUnprofiledMethodsByClassLayoutOrder()
3800 qsort(&m_MethodCompilationOrder[m_iUntrainedMethod], m_MethodCompilationOrder.GetCount() - m_iUntrainedMethod, sizeof(ZapMethodHeader *), LayoutOrderCmp);