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.h
6//
7
8//
9// NGEN-specific infrastructure for writing PE files.
10//
11// ======================================================================================
12
13#ifndef __ZAPIMAGE_H__
14#define __ZAPIMAGE_H__
15
16class ZapMetaData;
17class ZapILMetaData;
18class ZapCorHeader;
19class ZapNativeHeader;
20class ZapVersionInfo;
21class ZapDependencies;
22class ZapCodeManagerEntry;
23
24class ZapReadyToRunHeader;
25
26class ZapInnerPtrTable;
27class ZapMethodEntryPointTable;
28class ZapWrapperTable;
29
30class ZapBaseRelocs;
31
32class ZapBlobWithRelocs;
33
34//class ZapGCInfoTable;
35#ifdef WIN64EXCEPTIONS
36class ZapUnwindDataTable;
37#endif
38
39class ZapImportTable;
40class ZapImportSectionsTable;
41class ZapImportSectionSignatures;
42
43class ZapVirtualSectionsTable;
44class DataImage;
45
46class ZapperStats;
47
48#undef SAFERELEASE
49#define SAFERELEASE(p) if ((p) != NULL) { IUnknown * _ = (p); (p) = NULL; _->Release(); };
50
51#if defined(_TARGET_X86_) || defined(_TARGET_AMD64_)
52#define DEFAULT_CODE_BUFFER_INIT 0xcc // breakpoint
53#else
54#define DEFAULT_CODE_BUFFER_INIT 0
55#endif
56
57#ifdef _TARGET_64BIT_
58// Optimize for speed
59#define DEFAULT_CODE_ALIGN 16
60#else
61// Optimize for size.
62#define DEFAULT_CODE_ALIGN 4
63#endif
64
65#ifdef _TARGET_ARM_
66#define MINIMUM_CODE_ALIGN 2
67#elif _TARGET_ARM64_
68#define MINIMUM_CODE_ALIGN 4
69#else
70#define MINIMUM_CODE_ALIGN 1
71#endif
72
73// Various zapper hashtables are preallocated based on the size of IL image to reduce amount of
74// rehashing we have to do. Turn ZAP_HASHTABLE_TUNING on to collect data for the tuning of initial hashtable sizes.
75// #define ZAP_HASHTABLE_TUNING
76
77#ifdef ZAP_HASHTABLE_TUNING
78
79#define PREALLOCATE_HASHTABLE(table, quotient, cbILImage) \
80 PREALLOCATE_HASHTABLE_NOT_NEEDED(table, cbILImage)
81
82#define PREALLOCATE_HASHTABLE_NOT_NEEDED(table, cbILImage) \
83 do { \
84 GetSvcLogger()->Printf(W("HashTable:\t%S\t%d\t%f\n"), #table, table.GetCount(), (double)table.GetCount() / (double)cbILImage); \
85 } while (0)
86
87#define PREALLOCATE_ARRAY(array, quotient, cbILImage) \
88 do { \
89 GetSvcLogger()->Printf(W("Array:\t%S\t%d\t%f\n"), #array, array.GetCount(), (double)array.GetCount() / (double)cbILImage); \
90 } while (0)
91
92#else // ZAP_HASHTABLE_TUNING
93
94#define PREALLOCATE_HASHTABLE(table, quotient, cbILImage) \
95 do { \
96 COUNT_T nSize = (COUNT_T)(quotient * \
97 ((double)table.s_density_factor_denominator / (double)table.s_density_factor_numerator) * \
98 cbILImage); \
99 if (nSize > table.s_minimum_allocation) \
100 table.Reallocate(nSize); \
101 } while (0)
102
103#define PREALLOCATE_HASHTABLE_NOT_NEEDED(table, cbILImage)
104
105#define PREALLOCATE_ARRAY(array, quotient, cbILImage) \
106 do { \
107 COUNT_T nSize = (COUNT_T)(quotient * \
108 cbILImage); \
109 array.Preallocate(nSize); \
110 } while (0)
111
112#endif // ZAP_HASHTABLE_TUNING
113
114//---------------------------------------------------------------------------------------
115//
116// ZapImportSectionType is enum describing import sections allocated in the image
117//
118enum ZapImportSectionType
119{
120 ZapImportSectionType_Handle, // Unspecified handle
121 ZapImportSectionType_TypeHandle, // Type and method handles have to have their own section so we can restore them correctly
122 ZapImportSectionType_MethodHandle,
123#ifdef _TARGET_ARM_
124 ZapImportSectionType_PCode, // Code pointers have to be in a own section on ARM because of they are tagged differently
125#endif
126 ZapImportSectionType_StringHandle, // String handles require special handling for interning
127 ZapImportSectionType_Count,
128
129 ZapImportSectionType_Hot = 0, // We have two sets of the section - hot and cold
130 ZapImportSectionType_Cold = ZapImportSectionType_Count,
131
132 ZapImportSectionType_Eager = 2 * ZapImportSectionType_Count, // And one section for eager loaded handles
133
134 ZapImportSectionType_Total = 2 * ZapImportSectionType_Count + 1,
135};
136
137#include "zaprelocs.h"
138#include "zapinfo.h"
139#include "zapcode.h"
140
141class ZapImage
142 : public ZapWriter
143 , public ICorCompileDataStore
144{
145 friend class Zapper;
146 friend class ZapInfo;
147 friend class ZapILMetaData;
148 friend class ZapImportTable;
149 friend class ZapCodeMethodDescs;
150 friend class ZapColdCodeMap;
151 friend class ZapReadyToRunHeader;
152
153 private:
154
155 Zapper *m_zapper;
156
157 //
158 // Output module
159 //
160
161 LPWSTR m_pOutputFileFullName; // Name of the temp ngen file to generate (including the path)
162
163 //
164 // Make all virtual section pointers public for now. It should be cleaned up as we get more sophisticated layout
165 // algorithm in place.
166 //
167public:
168 ZapPhysicalSection * m_pTextSection;
169
170 //
171 // All virtual sections of the native image in alphabetical order
172 //
173
174 ZapVirtualSection * m_pBaseRelocsSection;
175 ZapVirtualSection * m_pCodeSection;
176 ZapVirtualSection * m_pColdCodeSection;
177 ZapVirtualSection * m_pDebugSection;
178 ZapVirtualSection * m_pDelayLoadInfoDelayListSectionEager;
179 ZapVirtualSection * m_pDelayLoadInfoDelayListSectionCold;
180 ZapVirtualSection * m_pDelayLoadInfoDelayListSectionHot;
181 ZapVirtualSection * m_pDelayLoadInfoTableSection[ZapImportSectionType_Total];
182 ZapVirtualSection * m_pStubsSection;
183 ZapVirtualSection * m_pEETableSection;
184 ZapVirtualSection * m_pExceptionSection;
185 ZapVirtualSection * m_pGCSection;
186 ZapVirtualSection * m_pHeaderSection;
187 ZapVirtualSection * m_pHelperTableSection;
188 ZapVirtualSection * m_pLazyHelperSection;
189 ZapVirtualSection * m_pLazyMethodCallHelperSection;
190 ZapVirtualSection * m_pHotCodeSection;
191 ZapVirtualSection * m_pHotGCSection;
192 ZapVirtualSection * m_pHotTouchedGCSection;
193 ZapVirtualSection * m_pILMetaDataSection;
194 ZapVirtualSection * m_pILSection;
195 ZapVirtualSection * m_pImportTableSection;
196 ZapVirtualSection * m_pInstrumentSection;
197 ZapVirtualSection * m_pMetaDataSection;
198 ZapVirtualSection * m_pReadOnlyDataSection;
199 ZapVirtualSection * m_pResourcesSection;
200 ZapVirtualSection * m_pWin32ResourceSection;
201 ZapVirtualSection * m_pStubDispatchCellSection;
202 ZapVirtualSection * m_pStubDispatchDataSection;
203 ZapVirtualSection * m_pDynamicHelperCellSection;
204 ZapVirtualSection * m_pDynamicHelperDataSection;
205 ZapVirtualSection * m_pVirtualImportThunkSection;
206 ZapVirtualSection * m_pExternalMethodThunkSection;
207 ZapVirtualSection * m_pExternalMethodCellSection;
208 ZapVirtualSection * m_pExternalMethodDataSection;
209 ZapVirtualSection * m_pHotRuntimeFunctionSection;
210 ZapVirtualSection * m_pRuntimeFunctionSection;
211 ZapVirtualSection * m_pColdRuntimeFunctionSection;
212 ZapVirtualSection * m_pHotCodeMethodDescsSection;
213 ZapVirtualSection * m_pCodeMethodDescsSection;
214 ZapVirtualSection * m_pHotRuntimeFunctionLookupSection;
215 ZapVirtualSection * m_pRuntimeFunctionLookupSection;
216 ZapVirtualSection * m_pColdCodeMapSection;
217#if defined(WIN64EXCEPTIONS)
218 ZapVirtualSection * m_pHotUnwindDataSection;
219 ZapVirtualSection * m_pUnwindDataSection;
220 ZapVirtualSection * m_pColdUnwindDataSection;
221#endif // defined(WIN64EXCEPTIONS)
222
223#ifdef FEATURE_READYTORUN_COMPILER
224 ZapVirtualSection * m_pAvailableTypesSection;
225#endif
226
227 // Preloader sections
228 ZapVirtualSection * m_pPreloadSections[CORCOMPILE_SECTION_COUNT];
229
230 ZapExceptionInfoLookupTable* m_pExceptionInfoLookupTable;
231public:
232 // TODO: Remove once all EE datastructures are converted to ZapNodes
233 ICorCompilePreloader * m_pPreloader;
234 DataImage * m_pDataImage;
235
236public:
237 // TODO: The stats should be removed once we have all information available in nidump
238 ZapperStats *m_stats;
239
240private:
241 IMetaDataAssemblyEmit *m_pAssemblyEmit; // native image manifest
242 ZapMetaData * m_pAssemblyMetaData;
243
244 ZapVersionInfo * m_pVersionInfo;
245 ZapDependencies * m_pDependencies;
246
247 SString m_pdbFileName;
248
249 ZapCodeManagerEntry * m_pCodeManagerEntry;
250
251 ZapBlob * m_pEEInfoTable;
252
253 //
254 // Auxiliary tables
255 //
256 ZapImportTable * m_pImportTable;
257
258 ZapImportSectionsTable * m_pImportSectionsTable;
259
260 ZapInnerPtrTable * m_pInnerPtrs;
261
262 ZapMethodEntryPointTable * m_pMethodEntryPoints;
263
264 ZapWrapperTable * m_pWrappers;
265
266 ZapBaseRelocs * m_pBaseRelocs;
267
268 ULONGLONG m_NativeBaseAddress;
269
270 ULONGLONG GetNativeBaseAddress()
271 {
272 return m_NativeBaseAddress;
273 }
274
275 void CalculateZapBaseAddress();
276
277 // Preallocate hashtables to avoid rehashing
278 void Preallocate();
279
280 ZapGCInfoTable * m_pGCInfoTable;
281
282#ifdef WIN64EXCEPTIONS
283 ZapUnwindDataTable * m_pUnwindDataTable;
284#endif
285
286 ZapImportSectionSignatures * m_pDelayLoadInfoDataTable[ZapImportSectionType_Total];
287 ZapImportSectionSignatures * m_pStubDispatchDataTable;
288 ZapImportSectionSignatures * m_pExternalMethodDataTable;
289 ZapImportSectionSignatures * m_pDynamicHelperDataTable;
290
291 ZapVirtualSectionsTable * m_pVirtualSectionsTable;
292
293 ZapDebugInfoTable * m_pDebugInfoTable;
294
295 ZapILMetaData * m_pILMetaData;
296
297 ZapCorHeader * m_pCorHeader;
298
299 ZapNode * m_pResources;
300
301 ZapNode * m_pNativeHeader;
302
303 ZapBlob * m_pNGenPdbDebugData;
304
305 ULONG m_totalHotCodeSize;
306 ULONG m_totalColdCodeSize;
307
308 ULONG m_totalCodeSizeInProfiledMethods;
309 ULONG m_totalColdCodeSizeInProfiledMethods;
310
311 //information to track the boundaries of the different subsections within
312 //the hot section.
313 COUNT_T m_iIBCMethod;
314 COUNT_T m_iGenericsMethod;
315 COUNT_T m_iUntrainedMethod;
316
317 //
318 // Input module
319 //
320
321 LPWSTR m_pModuleFileName; // file name of the module being compiled, including path
322 CORINFO_MODULE_HANDLE m_hModule; // Module being compiled
323 PEDecoder m_ModuleDecoder;
324 IMDInternalImport * m_pMDImport;
325 bool m_fManifestModule; // Is this the assembly-manifest-module
326 bool m_fHaveProfileData;
327
328 ZapNode ** m_pHelperThunks; // Array of on demand allocated JIT helper thunks
329
330 //
331 // Profile source
332 //
333
334 BYTE * m_profileDataFile;
335 BYTE * m_pRawProfileData;
336 COUNT_T m_cRawProfileData;
337 CorProfileData * m_pCorProfileData;
338
339public:
340 enum CompileStatus {
341 // Failure status values are negative
342 LOOKUP_FAILED = -2,
343 COMPILE_FAILED = -1,
344
345 // Info status values are [0..9]
346 NOT_COMPILED = 0,
347 COMPILE_EXCLUDED = 1,
348 COMPILE_HOT_EXCLUDED = 2,
349 COMPILE_COLD_EXCLUDED = 3,
350
351 // Successful status values are 10 or greater
352 COMPILE_SUCCEED = 10,
353 ALREADY_COMPILED = 11
354 };
355
356private:
357 // A hash table entry that contains the profile infomation and the CompileStatus for a given method
358 struct ProfileDataHashEntry
359 {
360 mdMethodDef md; // The method.token, also used as the key for the ProfileDataHashTable
361 DWORD size; // The size of the CORBBTPROF_BLOCK_DATA region, set by ZapImage::hashBBProfileData()
362 ULONG pos; // the offset to the CORBBTPROF_BLOCK_DATA region, set by ZapImage::hashBBProfileData()
363
364 unsigned flags; // The methodProfilingDataFlags, set by ZapImage::CompileHotRegion()
365 CompileStatus status; // The compileResult, set by ZapImage::CompileHotRegion()
366 };
367
368 class ProfileDataHashTraits : public NoRemoveSHashTraits< DefaultSHashTraits<ProfileDataHashEntry> >
369 {
370 public:
371 typedef const mdMethodDef key_t;
372
373 static key_t GetKey(element_t e)
374 {
375 LIMITED_METHOD_CONTRACT;
376 return e.md;
377 }
378 static BOOL Equals(key_t k1, key_t k2)
379 {
380 LIMITED_METHOD_CONTRACT;
381 return k1 == k2;
382 }
383 static count_t Hash(key_t k)
384 {
385 LIMITED_METHOD_CONTRACT;
386 return (count_t)k;
387 }
388
389 static const element_t Null()
390 {
391 LIMITED_METHOD_CONTRACT;
392 ProfileDataHashEntry e;
393 e.md = 0;
394 e.size = 0;
395 e.pos = 0;
396 e.flags = 0;
397 e.status = NOT_COMPILED;
398 return e;
399 }
400
401 static bool IsNull(const element_t &e)
402 {
403 LIMITED_METHOD_CONTRACT;
404 // returns true if both md and pos are zero
405 return (e.md == 0) && (e.pos == 0);
406 }
407 };
408 typedef SHash<ProfileDataHashTraits> ProfileDataHashTable;
409
410 ProfileDataHashTable profileDataHashTable;
411
412 SArray<SString, FALSE> fileNotFoundErrorsTable;
413 void FileNotFoundError(LPCWSTR pszMessage);
414
415public:
416 struct ProfileDataSection
417 {
418 BYTE *pData;
419 DWORD dataSize;
420 DWORD tableSize;
421 CORBBTPROF_TOKEN_INFO *pTable;
422 };
423
424private:
425 ProfileDataSection m_profileDataSections[SectionFormatCount];
426
427 DWORD m_profileDataNumRuns;
428
429 CorInfoRegionKind m_currentRegionKind;
430
431 BOOL IsAssemblyBeingCompiled(CORINFO_MODULE_HANDLE module) {
432 return ((module == m_hModule) ||
433 (m_zapper->m_pEECompileInfo->GetModuleAssembly(module) == m_zapper->m_hAssembly));
434 }
435
436 class ZapMethodTraits : public NoRemoveSHashTraits< DefaultSHashTraits<ZapMethodHeader *> >
437 {
438 public:
439 typedef CORINFO_METHOD_HANDLE key_t;
440
441 static key_t GetKey(element_t e)
442 {
443 LIMITED_METHOD_CONTRACT;
444 return e->GetHandle();
445 }
446 static BOOL Equals(key_t k1, key_t k2)
447 {
448 LIMITED_METHOD_CONTRACT;
449 return k1 == k2;
450 }
451 static count_t Hash(key_t k)
452 {
453 LIMITED_METHOD_CONTRACT;
454 return (count_t)(size_t)k;
455 }
456 };
457
458 typedef SHash<ZapMethodTraits> ZapMethodHashTable;
459
460 ZapMethodHashTable m_CompiledMethods;
461
462 SArray<ZapMethodHeader *> m_MethodCompilationOrder;
463
464 SArray<ZapGCInfo *> m_PrioritizedGCInfo;
465
466#ifndef FEATURE_FULL_NGEN
467 class MethodCodeTraits : public NoRemoveSHashTraits< DefaultSHashTraits<ZapMethodHeader *> >
468 {
469 public:
470 typedef ZapMethodHeader * key_t;
471
472 static FORCEINLINE key_t GetKey(element_t e)
473 {
474 LIMITED_METHOD_CONTRACT;
475 return e;
476 }
477
478 static BOOL Equals(key_t k1, key_t k2);
479 static COUNT_T Hash(key_t k);
480
481 static element_t Null() { LIMITED_METHOD_CONTRACT; return NULL; }
482 static bool IsNull(const element_t &e) { LIMITED_METHOD_CONTRACT; return e == NULL; }
483 };
484
485 typedef SHash <MethodCodeTraits> ZapMethodCodeHashTable;
486
487 ZapMethodCodeHashTable m_CodeDeduplicator;
488#endif // FEATURE_FULL_NGEN
489
490 struct ClassLayoutOrderEntry
491 {
492 CORINFO_CLASS_HANDLE m_cls;
493 unsigned m_order;
494
495 ClassLayoutOrderEntry()
496 : m_cls(0), m_order(0)
497 {
498 }
499
500 ClassLayoutOrderEntry(CORINFO_CLASS_HANDLE cls, unsigned order)
501 : m_cls(cls), m_order(order)
502 {
503 }
504 };
505
506 class ClassLayoutOrderTraits : public NoRemoveSHashTraits< DefaultSHashTraits<ClassLayoutOrderEntry> >
507 {
508 public:
509 typedef CORINFO_CLASS_HANDLE key_t;
510
511 static key_t GetKey(element_t e)
512 {
513 LIMITED_METHOD_CONTRACT;
514 return e.m_cls;
515 }
516 static BOOL Equals(key_t k1, key_t k2)
517 {
518 LIMITED_METHOD_CONTRACT;
519 return k1 == k2;
520 }
521 static count_t Hash(key_t k)
522 {
523 LIMITED_METHOD_CONTRACT;
524 return (count_t)(size_t)k;
525 }
526 static const element_t Null() { LIMITED_METHOD_CONTRACT; return element_t(0,0); }
527 static bool IsNull(const element_t &e) { LIMITED_METHOD_CONTRACT; return e.m_cls == 0; }
528 };
529
530 typedef SHash<ClassLayoutOrderTraits> ClassLayoutOrderHashTable;
531
532 ClassLayoutOrderHashTable m_ClassLayoutOrder;
533
534 // See ComputeClassLayoutOrder for an explanation of these flags
535 #define UNSEEN_CLASS_FLAG (0x80000000)
536 #define METHOD_INDEX_FLAG (0x40000000)
537
538 // The class layout order needs to be initialized with the first index
539 // in m_MethodCompilationOrder of a method in the given class.
540 inline void InitializeClassLayoutOrder(CORINFO_CLASS_HANDLE cls, unsigned order)
541 {
542 WRAPPER_NO_CONTRACT;
543
544 if (!m_ClassLayoutOrder.LookupPtr(cls))
545 {
546 ClassLayoutOrderEntry entry(cls, order | UNSEEN_CLASS_FLAG | METHOD_INDEX_FLAG);
547 m_ClassLayoutOrder.Add(entry);
548 }
549 }
550
551public:
552 inline unsigned LookupClassLayoutOrder(CORINFO_CLASS_HANDLE cls)
553 {
554 WRAPPER_NO_CONTRACT;
555
556 const ClassLayoutOrderEntry *pEntry = m_ClassLayoutOrder.LookupPtr(cls);
557 _ASSERTE(!pEntry || pEntry->m_order != 0);
558
559 return pEntry ? pEntry->m_order : 0;
560 }
561
562private:
563
564 //
565 // The image layout algorithm
566 //
567
568 enum CodeType
569 {
570 ProfiledHot,
571 ProfiledCold,
572 Unprofiled
573 };
574
575 ZapVirtualSection * GetCodeSection(CodeType codeType);
576 ZapVirtualSection * GetRuntimeFunctionSection(CodeType codeType);
577 ZapVirtualSection * GetCodeMethodDescSection(CodeType codeType);
578 ZapVirtualSection * GetUnwindInfoLookupSection(CodeType codeType);
579
580#if defined(WIN64EXCEPTIONS)
581 ZapVirtualSection * GetUnwindDataSection(CodeType codeType);
582#endif
583
584 void GetCodeCompilationRange(CodeType codeType, COUNT_T * start, COUNT_T * end);
585
586 void OutputCode(CodeType codeType);
587 void OutputCodeInfo(CodeType codeType);
588
589 void OutputGCInfo();
590
591 void OutputDebugInfo();
592 void OutputProfileData();
593
594 void OutputEntrypointsTableForReadyToRun();
595 void OutputDebugInfoForReadyToRun();
596 void OutputTypesTableForReadyToRun(IMDInternalImport * pMDImport);
597 void OutputInliningTableForReadyToRun();
598 void OutputProfileDataForReadyToRun();
599
600 void CopyDebugDirEntry();
601 void CopyWin32VersionResource();
602
603 void OutputManifestMetadata();
604 void OutputTables();
605
606 // Assign RVAs to all ZapNodes
607 void ComputeRVAs();
608
609 HANDLE GenerateFile(LPCWSTR wszOutputFileName, CORCOMPILE_NGEN_SIGNATURE * pNativeImageSig);
610
611 void PrintStats(LPCWSTR wszOutputFileName);
612
613 bool m_fHasClassLayoutOrder;
614
615 void ComputeClassLayoutOrder();
616 void SortUnprofiledMethodsByClassLayoutOrder();
617
618 HRESULT GetPdbFileNameFromModuleFilePath(__in_z const wchar_t *pwszModuleFilePath,
619 __out_ecount(dwPdbFileNameBufferSize) char * pwszPdbFileName,
620 DWORD dwPdbFileNameBufferSize);
621
622public:
623 ZapImage(Zapper *zapper);
624 virtual ~ZapImage();
625
626 // ----------------------------------------------------------------------------------------------------------
627 //
628 // Utility function for converting ZapWriter * to ZapImage *. This cast should not be done directly by the code
629 // so that the relationship between ZapWriter and ZapImage is abstracted away.
630 //
631 static ZapImage * GetImage(ZapWriter * pZapWriter)
632 {
633 return (ZapImage *)pZapWriter;
634 }
635
636 // ----------------------------------------------------------------------------------------------------------
637 //
638 // Add relocation record. This method is meant to be called from the Save method of custom ZapNodes right
639 // before the given datastructure is written into the native image.
640 //
641 // Arguments:
642 // pSrc - the datastructure being written
643 // offset - offset of the relocation within the datastructure
644 // pTarget - target of the relocation
645 // targetOffset - adjusment of the target (usually 0)
646 // type - relocation type (IMAGE_REL_BASED_XXX enum, note that we have private additions to this enum:
647 // IMAGE_REL_BASED_PTR - architecture specific reloc of virtual address
648 // IMAGE_REL_BASED_ABSOLUTE_TAGGED - absolute stored in the middle 30-bits, used for fixups.
649 // IMAGE_REL_BASED_RELPTR - pointer stored as address relative delta
650 // IMAGE_REL_BASED_RELPTR32 - pointer stored as address relative 32-bit delta
651 //
652 void WriteReloc(PVOID pSrc, int offset, ZapNode * pTarget, int targetOffset, ZapRelocationType type);
653
654 void Open(CORINFO_MODULE_HANDLE hModule, IMetaDataAssemblyEmit *pEmit);
655
656 void InitializeSections();
657 void InitializeSectionsForReadyToRun();
658
659 // Wrapper of ZapWriter::NewVirtualSection that sets sectionType
660 ZapVirtualSection * NewVirtualSection(ZapPhysicalSection * pPhysicalSection, DWORD sectionType /* ZapVirtualSectionType */, DWORD dwAlignment = 16, ZapVirtualSection * pInsertAfter = NULL)
661 {
662 ZapVirtualSection * pSection = ZapWriter::NewVirtualSection(pPhysicalSection, dwAlignment, pInsertAfter);
663 pSection->SetSectionType(sectionType);
664 return pSection;
665 }
666
667 void AllocateVirtualSections();
668
669 HANDLE SaveImage(LPCWSTR wszOutputFileName, LPCWSTR wszDllPath, CORCOMPILE_NGEN_SIGNATURE * pNativeImageSig);
670
671 void Preload();
672 void LinkPreload();
673
674 void SetVersionInfo(CORCOMPILE_VERSION_INFO * pVersionInfo);
675 void SetDependencies(CORCOMPILE_DEPENDENCY *pDependencies, DWORD cDependencies);
676 void SetPdbFileName(const SString &strFileName);
677
678#ifdef WIN64EXCEPTIONS
679 void SetRuntimeFunctionsDirectoryEntry();
680#endif
681
682 void SaveCorHeader();
683 void SaveNativeHeader();
684 void SaveCodeManagerEntry();
685
686 void Compile();
687
688 ZapMethodHeader * GetCompiledMethod(CORINFO_METHOD_HANDLE handle)
689 {
690 return m_CompiledMethods.Lookup(handle);
691 }
692
693 static void __stdcall TryCompileMethodStub(LPVOID pContext, CORINFO_METHOD_HANDLE hStub, CORJIT_FLAGS jitFlags);
694
695 BOOL IsVTableGapMethod(mdMethodDef md);
696
697 CompileStatus TryCompileMethodDef(mdMethodDef md, unsigned methodProfilingDataFlags);
698 CompileStatus TryCompileInstantiatedMethod(CORINFO_METHOD_HANDLE handle, unsigned methodProfilingDataFlags);
699 CompileStatus TryCompileMethodWorker(CORINFO_METHOD_HANDLE handle, mdMethodDef md, unsigned methodProfilingDataFlags);
700
701 BOOL ShouldCompileMethodDef(mdMethodDef md);
702 BOOL ShouldCompileInstantiatedMethod(CORINFO_METHOD_HANDLE handle);
703
704 bool canIntraModuleDirectCall(CORINFO_METHOD_HANDLE callerFtn,
705 CORINFO_METHOD_HANDLE targetFtn,
706 CorInfoIndirectCallReason *pReason = NULL,
707 CORINFO_ACCESS_FLAGS accessFlags = CORINFO_ACCESS_ANY);
708
709 CORINFO_MODULE_HANDLE GetModuleHandle()
710 {
711 return m_hModule;
712 }
713
714 IMetaDataAssemblyEmit * GetAssemblyEmit()
715 {
716 return m_pAssemblyEmit;
717 }
718
719 ZapWrapperTable * GetWrappers()
720 {
721 return m_pWrappers;
722 }
723
724 ZapImportTable * GetImportTable()
725 {
726 return m_pImportTable;
727 }
728
729 ZapImportSectionsTable * GetImportSectionsTable()
730 {
731 return m_pImportSectionsTable;
732 }
733
734 ZapNode * GetEEInfoTable()
735 {
736 return m_pEEInfoTable;
737 }
738
739 ZapReadyToRunHeader * GetReadyToRunHeader()
740 {
741 _ASSERTE(IsReadyToRunCompilation());
742 return (ZapReadyToRunHeader *)m_pNativeHeader;
743 }
744
745 ZapNode * GetInnerPtr(ZapNode * pNode, SSIZE_T offset);
746
747 CorInfoRegionKind GetCurrentRegionKind()
748 {
749 return m_currentRegionKind;
750 }
751
752 //
753 // Called from ZapImportTable::PlaceBlob
754 // to determine wheather to place the new signature Blob
755 // into the HotImports or the ColdImports section.
756 //
757 // The Assert will fire if BeginRegion was not called
758 // to setup the region
759 //
760 bool IsCurrentCodeRegionHot()
761 {
762 if (GetCurrentRegionKind() == CORINFO_REGION_HOT)
763 {
764 return true;
765 }
766 else if (GetCurrentRegionKind() == CORINFO_REGION_COLD)
767 {
768 return false;
769 }
770 _ASSERTE(!"unsupported RegionKind");
771 return false;
772 }
773
774 //
775 // Marks the start of a region where we want to place any
776 // new signature Blobs into the Hot/Cold region
777 //
778 void BeginRegion(CorInfoRegionKind regionKind)
779 {
780 _ASSERTE(GetCurrentRegionKind() == CORINFO_REGION_NONE);
781 m_currentRegionKind = regionKind;
782 }
783
784 //
785 // Marks the end of a region and we no longer expect to
786 // need any new signature Blobs
787 //
788 void EndRegion(CorInfoRegionKind regionKind)
789 {
790 _ASSERTE(GetCurrentRegionKind() == regionKind);
791 m_currentRegionKind = CORINFO_REGION_NONE;
792 }
793
794 ICorCompilationDomain * GetDomain()
795 {
796 return m_zapper->m_pDomain;
797 }
798
799 ICorDynamicInfo * GetJitInfo()
800 {
801 return m_zapper->m_pEEJitInfo;
802 }
803
804 ICorCompileInfo * GetCompileInfo()
805 {
806 return m_zapper->m_pEECompileInfo;
807 }
808
809 ZapperOptions * GetZapperOptions()
810 {
811 return m_zapper->m_pOpt;
812 }
813
814 ZapNode * GetHelperThunkIfExists(CorInfoHelpFunc ftnNum)
815 {
816 return m_pHelperThunks[ftnNum];
817 }
818
819 ZapNode * GetHelperThunk(CorInfoHelpFunc ftnNum);
820
821 BOOL HasClassLayoutOrder()
822 {
823 return m_fHasClassLayoutOrder;
824 }
825
826 HRESULT PrintTokenDescription(CorZapLogLevel level, mdToken token);
827
828 // ICorCompileDataStore
829
830 // Returns ZapImage
831 virtual ZapImage * GetZapImage();
832 void Error(mdToken token, HRESULT error, UINT resID, LPCWSTR message);
833
834 // Returns virtual section for EE datastructures
835 ZapVirtualSection * GetSection(CorCompileSection section)
836 {
837 return m_pPreloadSections[section];
838 }
839
840 HRESULT LocateProfileData();
841 HRESULT parseProfileData ();
842 HRESULT convertProfileDataFromV1();
843 void RehydrateBasicBlockSection();
844 void RehydrateTokenSection(int sectionFormat, unsigned int flagTable[255]);
845 void RehydrateBlobStream();
846 HRESULT RehydrateProfileData();
847 HRESULT hashBBProfileData ();
848 void hashBBUpdateFlagsAndCompileResult(mdToken token, unsigned methodProfilingDataFlags, CompileStatus compileResult);
849
850 void LoadProfileData();
851 CorProfileData * NewProfileData();
852 CorProfileData * GetProfileData();
853 bool CanConvertIbcData();
854
855 CompileStatus CompileProfileDataWorker(mdToken token, unsigned methodProfilingDataFlags);
856
857 void ProfileDisableInlining();
858 void CompileHotRegion();
859 void CompileColdRegion();
860 void PlaceMethodIL();
861};
862
863class BinaryWriter
864{
865private:
866 char *m_buffer;
867 unsigned int m_length;
868 unsigned int m_currentPosition;
869 ZapHeap *m_heap;
870
871private:
872 // Make sure that the buffer is at least newLength bytes long;
873 // expand it if necessary.
874 void RequireLength(unsigned int newLength)
875 {
876 if (newLength <= m_length)
877 {
878 return;
879 }
880
881 if (newLength < (m_length * 3) / 2)
882 {
883 newLength = (m_length * 3) / 2;
884 }
885
886 char *newBuffer = new (m_heap) char[newLength];
887
888 memcpy(newBuffer, m_buffer, m_length);
889
890 m_length = newLength;
891 m_buffer = newBuffer;
892 }
893
894public:
895 BinaryWriter(unsigned int initialLength, ZapHeap *heap)
896 {
897 m_heap = heap;
898 m_length = initialLength;
899 m_buffer = new (m_heap) char[initialLength];
900 m_currentPosition = 0;
901 }
902
903 template <typename T>
904 void WriteAt(unsigned int position, const T &v)
905 {
906 RequireLength(position + sizeof(T));
907
908 *(T *)(m_buffer + position) = v;
909 }
910
911 template <typename T>
912 void Write(const T &v)
913 {
914 WriteAt<T>(m_currentPosition, v);
915 m_currentPosition += sizeof(T);
916 }
917
918 void Write(const char *data, unsigned int length)
919 {
920 RequireLength(m_currentPosition + length);
921
922 memcpy(m_buffer + m_currentPosition, data, length);
923 m_currentPosition += length;
924 }
925
926 BYTE *GetBuffer()
927 {
928 return (BYTE *)m_buffer;
929 }
930
931 unsigned int GetWrittenSize()
932 {
933 return m_currentPosition;
934 }
935};
936
937class ProfileReader
938{
939public:
940 ProfileReader(void *buffer, ULONG length)
941 {
942 profileBuffer = (char *) buffer;
943 bufferSize = length;
944 currentPos = 0;
945 }
946
947 bool Seek(ULONG pos)
948 {
949 if (pos <= bufferSize)
950 {
951 currentPos = pos;
952 return true;
953 }
954 else
955 {
956 _ASSERTE(!"ProfileReader: attempt to seek out of bounds");
957 return false;
958 }
959 }
960
961 void *Read(ULONG size)
962 {
963 ULONG oldPos = currentPos;
964
965 if (!Seek(currentPos + size))
966 {
967 return NULL;
968 }
969
970 return (void *)(profileBuffer + oldPos);
971 }
972
973 template <typename T> T Read()
974 {
975 T* pResult = (T*)Read(sizeof(T));
976
977 if (!pResult)
978 {
979 ThrowHR(E_FAIL);
980 }
981
982 return *pResult;
983 }
984
985 // Read an integer a la BinaryReader.Read7BitEncodedInt.
986 unsigned int Read7BitEncodedInt()
987 {
988 unsigned int result = 0;
989 int shift = 0;
990 unsigned char current = 0x80;
991
992 while ((currentPos < bufferSize) &&
993 (shift <= 28))
994 {
995 current = profileBuffer[currentPos++];
996 result |= (current & 0x7f) << shift;
997 shift += 7;
998
999 if (!(current & 0x80))
1000 {
1001 return result;
1002 }
1003 }
1004
1005 _ASSERTE(!"Improperly encoded value");
1006 ThrowHR(E_FAIL);
1007 }
1008
1009 // Read a token given a 'memory' value--the last token of this type read
1010 // from the stream. The encoding takes advantage of the fact that two
1011 // adjacent tokens in the file are usually of the same type, and therefore
1012 // share a high byte. With the high byte removed the rest of the token can
1013 // be encoded more efficiently.
1014 mdToken ReadTokenWithMemory(mdToken &memory)
1015 {
1016 mdToken current;
1017 mdToken result;
1018
1019 current = Read7BitEncodedInt();
1020
1021 unsigned char highByte = ((current >> 24) & 0xff);
1022
1023 if (highByte == 0)
1024 {
1025 result = current | (memory & 0xff000000);
1026 }
1027 else if (highByte == 0xff)
1028 {
1029 result = current & 0x00ffffff;
1030 }
1031 else
1032 {
1033 result = current;
1034 }
1035
1036 memory = result;
1037
1038 return result;
1039 }
1040
1041 // Read a 32-bit flag value using a lookup table built while processing the
1042 // file. Flag values are represented by a one-byte index. If the index
1043 // hasn't occurred before in the file, it is followed by the four-byte flag
1044 // value it represents. The index 255 is used as an escape code--it is
1045 // always followed by a flag value.
1046 // flagTable must have 255 entries and they must all start as 0xFFFFFFFF.
1047 unsigned int ReadFlagWithLookup(unsigned int flagTable[255])
1048 {
1049 unsigned char index;
1050 unsigned int flags;
1051
1052 index = Read<unsigned char>();
1053
1054 if ((index < 255) && (flagTable[index] != 0xffffffff))
1055 {
1056 return flagTable[index];
1057 }
1058
1059 flags = Read<unsigned int>();
1060
1061 if (index < 255)
1062 {
1063 flagTable[index] = flags;
1064 }
1065
1066 return flags;
1067 }
1068
1069 ULONG GetCurrentPos()
1070 {
1071 _ASSERTE(currentPos <= bufferSize);
1072 return currentPos;
1073 }
1074
1075private:
1076 char *profileBuffer;
1077 ULONG bufferSize;
1078 ULONG currentPos;
1079};
1080
1081struct RSDS {
1082 DWORD magic;
1083 GUID signature;
1084 DWORD age;
1085 char path[MAX_LONGPATH];
1086};
1087
1088#define SEEK(pos) \
1089 if (!profileReader.Seek(pos)) return E_FAIL;
1090
1091#define READ_SIZE(dst,type,size) \
1092 dst = (type *) profileReader.Read(size); \
1093 if (!dst) return E_FAIL;
1094
1095#define READ(dst,type) \
1096 READ_SIZE(dst,type,sizeof(type))
1097
1098#endif // __ZAPIMAGE_H__
1099