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