1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
9 // ZapNodes for everything directly related to zapping of native code
11 // code:ZapMethodHeader
12 // code:ZapMethodEntryPoint
13 // code:ZapMethodEntryPointTable
15 // code:ZapProfileData
16 // code:ZapHelperTable
17 // code:ZapGCInfoTable
21 // ======================================================================================
26 // Forward declarations
28 class ZapBlobWithRelocs;
31 typedef ZapNode ZapGCInfo;
33 #if defined(WIN64EXCEPTIONS)
36 typedef ZapBlob ZapGCInfo;
40 typedef ZapBlob ZapDebugInfo;
41 typedef ZapBlob ZapFixupInfo;
43 typedef ZapBlobWithRelocs ZapExceptionInfo;
45 typedef ZapBlob ZapExceptionInfo;
54 class ZapGCRefMapTable;
56 //---------------------------------------------------------------------------------------
58 // ZapMethodHeader is the main node that all information about the compiled code is hanging from
60 class ZapMethodHeader : public ZapNode
62 // All other kinds of method headers are tightly coupled with the main method header
63 friend class ZapProfileData;
64 friend class ZapCodeMethodDescs;
65 friend class ZapColdCodeMap;
67 friend class MethodCodeComparer;
69 friend class ZapImage;
72 CORINFO_METHOD_HANDLE m_handle;
73 CORINFO_CLASS_HANDLE m_classHandle;
75 ZapBlobWithRelocs * m_pCode;
76 ZapBlobWithRelocs * m_pColdCode; // May be NULL
78 ZapUnwindInfo * m_pUnwindInfo;
79 ZapUnwindInfo * m_pColdUnwindInfo; // May be NULL
81 #ifdef WIN64EXCEPTIONS
82 ZapUnwindInfo * m_pUnwindInfoFragments; // Linked list of all unwind info fragments
85 ZapBlobWithRelocs * m_pROData; // May be NULL
87 ZapBlobWithRelocs * m_pProfileData; // May be NULL
89 ZapGCInfo * m_pGCInfo;
90 ZapDebugInfo * m_pDebugInfo;
94 ZapImport ** m_pFixupList; // Valid before place phase
95 ZapFixupInfo * m_pFixupInfo; // Valid after place phase
98 ZapExceptionInfo * m_pExceptionInfo; // May be NULL
100 unsigned m_ProfilingDataFlags;
102 unsigned m_compilationOrder;
103 unsigned m_cachedLayoutOrder;
112 CORINFO_METHOD_HANDLE GetHandle()
117 CORINFO_CLASS_HANDLE GetClassHandle()
119 return m_classHandle;
122 DWORD GetMethodIndex()
124 return m_methodIndex;
127 ZapBlobWithRelocs * GetCode()
132 ZapBlobWithRelocs * GetColdCode()
139 return m_pFixupList != NULL;
142 ZapNode * GetFixupList()
147 ZapDebugInfo * GetDebugInfo()
152 unsigned GetCompilationOrder()
154 return m_compilationOrder;
157 unsigned GetCachedLayoutOrder()
159 return m_cachedLayoutOrder;
161 virtual ZapNodeType GetType()
163 return ZapNodeType_MethodHeader;
166 // Iterate over as many of the methods called by this method
167 // as are easy to determine. Currently this is implemented
168 // by walking the Reloc list and so is only as complete as
169 // the current state of the Relocs. Note that the implementation
170 // ignores virtual calls and calls in the cold code section.
171 class PartialTargetMethodIterator
174 PartialTargetMethodIterator(ZapMethodHeader* pMethod)
177 ZapBlobWithRelocs * pCode = pMethod->GetCode();
178 m_pCurReloc = pCode ? pCode->GetRelocs() : NULL;
181 BOOL GetNext(CORINFO_METHOD_HANDLE *pHnd);
184 ZapMethodHeader* m_pMethod;
185 ZapReloc* m_pCurReloc;
190 #if defined(_TARGET_X86_)
191 class ZapCodeBlob : public ZapBlobWithRelocs
194 ZapCodeBlob(SIZE_T cbSize)
195 : ZapBlobWithRelocs(cbSize)
200 static ZapCodeBlob * NewAlignedBlob(ZapWriter * pWriter, PVOID pData, SIZE_T cbSize, SIZE_T cbAlignment);
202 virtual DWORD ComputeRVA(ZapWriter * pZapWriter, DWORD dwPos);
205 typedef ZapBlobWithRelocs ZapCodeBlob;
208 class ZapCodeMethodDescs : public ZapNode
210 COUNT_T m_iStartMethod;
211 COUNT_T m_iEndMethod;
212 COUNT_T m_nUnwindInfos;
215 ZapCodeMethodDescs(COUNT_T startMethod, COUNT_T endMethod, COUNT_T nUnwindInfos)
216 : m_iStartMethod(startMethod), m_iEndMethod(endMethod), m_nUnwindInfos(nUnwindInfos)
220 virtual UINT GetAligment()
222 return sizeof(DWORD);
225 virtual DWORD GetSize()
227 return m_nUnwindInfos * sizeof(DWORD);
230 virtual ZapNodeType GetType()
232 return ZapNodeType_CodeManagerMap;
235 virtual void Save(ZapWriter * pZapWriter);
238 //---------------------------------------------------------------------------------------
240 // ZapMethodEntryPoint is special type of placeholder. Unlike normal placeholder, it
241 // carries extra CORINFO_ACCESS_FLAGS that is used to opt into the direct call even
242 // when it would not be otherwise possible.
244 class ZapMethodEntryPoint : public ZapNode
246 CORINFO_METHOD_HANDLE m_handle; // Target method being called
247 BYTE m_accessFlags; // CORINFO_ACCESS_FLAGS
248 BYTE m_fUsed; // Entrypoint is used - needs to be resolved
250 ZapNode *m_pEntryPoint; // only used for abstract methods to remember the precode
253 ZapMethodEntryPoint(CORINFO_METHOD_HANDLE handle, CORINFO_ACCESS_FLAGS accessFlags)
254 : m_handle(handle), m_accessFlags(static_cast<BYTE>(accessFlags))
258 virtual ZapNodeType GetType()
260 return ZapNodeType_MethodEntryPoint;
263 CORINFO_METHOD_HANDLE GetHandle()
268 CORINFO_ACCESS_FLAGS GetAccessFlags()
270 return (CORINFO_ACCESS_FLAGS)m_accessFlags;
283 void Resolve(ZapImage * pImage);
286 class ZapMethodEntryPointTable
288 struct MethodEntryPointKey
290 MethodEntryPointKey(CORINFO_METHOD_HANDLE handle, CORINFO_ACCESS_FLAGS accessFlags)
291 : m_handle(handle), m_accessFlags(accessFlags)
295 CORINFO_METHOD_HANDLE m_handle; // Target method being called
296 CORINFO_ACCESS_FLAGS m_accessFlags;
299 class MethodEntryPointTraits : public NoRemoveSHashTraits< DefaultSHashTraits<ZapMethodEntryPoint *> >
302 typedef MethodEntryPointKey key_t;
304 static key_t GetKey(element_t e)
306 LIMITED_METHOD_CONTRACT;
307 return MethodEntryPointKey(e->GetHandle(), e->GetAccessFlags());
309 static BOOL Equals(key_t k1, key_t k2)
311 LIMITED_METHOD_CONTRACT;
312 return (k1.m_handle == k2.m_handle) && (k1.m_accessFlags == k2.m_accessFlags);
314 static count_t Hash(key_t k)
316 LIMITED_METHOD_CONTRACT;
317 return (count_t)(size_t)k.m_handle ^ (count_t)k.m_accessFlags;
320 static const element_t Null() { LIMITED_METHOD_CONTRACT; return NULL; }
321 static bool IsNull(const element_t &e) { LIMITED_METHOD_CONTRACT; return e == NULL; }
324 typedef SHash< MethodEntryPointTraits > MethodEntryPointTable;
326 MethodEntryPointTable m_entries;
330 ZapMethodEntryPointTable(ZapImage * pImage)
335 void Preallocate(COUNT_T cbILImage)
337 PREALLOCATE_HASHTABLE(ZapMethodEntryPointTable::m_entries, 0.0018, cbILImage);
340 ZapMethodEntryPoint * GetMethodEntryPoint(CORINFO_METHOD_HANDLE handle, CORINFO_ACCESS_FLAGS accessFlags);
342 ZapNode * CanDirectCall(ZapMethodEntryPoint * pMethodEntryPoint, ZapMethodHeader * pCaller);
347 //---------------------------------------------------------------------------------------
349 // Zapping of unwind info
351 class ZapUnwindInfo : public ZapNode
355 DWORD m_dwStartOffset;
358 ZapNode * m_pUnwindData;
360 ZapUnwindInfo * m_pNextFragment;
363 ZapUnwindInfo(ZapNode * pCode, DWORD dwStartOffset, DWORD dwEndOffset, ZapNode * pUnwindData = NULL)
365 m_dwStartOffset(dwStartOffset),
366 m_dwEndOffset(dwEndOffset),
367 m_pUnwindData(pUnwindData)
376 DWORD GetStartOffset()
378 return m_dwStartOffset;
383 return m_dwEndOffset;
386 DWORD GetStartAddress()
388 return m_pCode->GetRVA() + GetStartOffset();
391 DWORD GetEndAddress()
393 return m_pCode->GetRVA() + GetEndOffset();
395 // Used to set unwind data lazily
396 void SetUnwindData(ZapNode * pUnwindData)
398 _ASSERTE(m_pUnwindData == NULL);
399 m_pUnwindData = pUnwindData;
402 ZapNode * GetUnwindData()
404 return m_pUnwindData;
407 void SetNextFragment(ZapUnwindInfo * pFragment)
409 _ASSERTE(m_pNextFragment == NULL);
410 m_pNextFragment = pFragment;
413 ZapUnwindInfo * GetNextFragment()
415 return m_pNextFragment;
418 virtual UINT GetAlignment()
420 return sizeof(ULONG);
423 virtual DWORD GetSize()
425 return sizeof(T_RUNTIME_FUNCTION);
428 virtual ZapNodeType GetType()
430 return ZapNodeType_UnwindInfo;
433 virtual void Save(ZapWriter * pZapWriter);
435 static int __cdecl CompareUnwindInfo(const void * a, const void * b);
438 #ifdef WIN64EXCEPTIONS
439 //---------------------------------------------------------------------------------------
441 // Zapping of unwind data
443 class ZapUnwindData : public ZapBlob
446 ZapUnwindData(SIZE_T cbSize)
451 virtual UINT GetAlignment();
453 virtual DWORD GetSize();
455 virtual ZapNodeType GetType()
457 return ZapNodeType_UnwindData;
460 BOOL IsFilterFunclet()
462 return GetType() == ZapNodeType_FilterFuncletUnwindData;
465 ZapNode * GetPersonalityRoutine(ZapImage * pImage);
466 virtual void Save(ZapWriter * pZapWriter);
468 static ZapUnwindData * NewUnwindData(ZapWriter * pWriter, PVOID pData, SIZE_T cbSize, BOOL fIsFilterFunclet);
471 class ZapFilterFuncletUnwindData : public ZapUnwindData
474 ZapFilterFuncletUnwindData(SIZE_T cbSize)
475 : ZapUnwindData(cbSize)
479 virtual ZapNodeType GetType()
481 return ZapNodeType_FilterFuncletUnwindData;
484 class ZapUnwindDataTable
488 struct ZapUnwindDataKey
490 ZapUnwindDataKey(PVOID pUnwindData, SIZE_T cbUnwindData, BOOL fIsFilterFunclet)
491 : m_unwindData(pUnwindData, cbUnwindData), m_fIsFilterFunclet(fIsFilterFunclet)
495 ZapBlob::SHashKey m_unwindData;
496 BOOL m_fIsFilterFunclet;
499 class ZapUnwindDataTraits : public NoRemoveSHashTraits< DefaultSHashTraits<ZapUnwindData *> >
502 typedef ZapUnwindDataKey key_t;
504 static key_t GetKey(element_t e)
506 LIMITED_METHOD_CONTRACT;
507 return ZapUnwindDataKey(e->GetData(), e->GetBlobSize(), e->IsFilterFunclet());
509 static BOOL Equals(key_t k1, key_t k2)
511 LIMITED_METHOD_CONTRACT;
512 return ZapBlob::SHashTraits::Equals(k1.m_unwindData, k2.m_unwindData) && (k1.m_fIsFilterFunclet == k2.m_fIsFilterFunclet);
514 static count_t Hash(key_t k)
516 LIMITED_METHOD_CONTRACT;
517 return ZapBlob::SHashTraits::Hash(k.m_unwindData) ^ k.m_fIsFilterFunclet;
520 static const element_t Null() { LIMITED_METHOD_CONTRACT; return NULL; }
521 static bool IsNull(const element_t &e) { LIMITED_METHOD_CONTRACT; return e == NULL; }
523 // Hashtable with all unwind data blobs. If two methods have unwind data
524 // we store it just once.
525 SHash< ZapUnwindDataTraits > m_blobs;
528 ZapUnwindDataTable(ZapImage * pImage)
533 void Preallocate(COUNT_T cbILImage)
535 PREALLOCATE_HASHTABLE(ZapUnwindDataTable::m_blobs, 0.0003, cbILImage);
538 ZapUnwindData * GetUnwindData(PVOID pBlob, SIZE_T cbBlob, BOOL fIsFilterFunclet);
540 #endif // WIN64EXCEPTIONS
543 //---------------------------------------------------------------------------------------
545 // Zapping of GC info
547 #ifdef WIN64EXCEPTIONS
548 class ZapGCInfo : public ZapUnwindData
553 ZapGCInfo(SIZE_T cbGCInfo, SIZE_T cbUnwindInfo)
554 : ZapUnwindData(cbUnwindInfo), m_cbGCInfo((DWORD)cbGCInfo)
556 if (m_cbGCInfo > ZAPWRITER_MAX_SIZE)
557 ThrowHR(COR_E_OVERFLOW);
560 virtual PBYTE GetData()
562 return (PBYTE)(this + 1);
567 return GetData() + GetUnwindInfoSize();
570 DWORD GetGCInfoSize()
575 PBYTE GetUnwindInfo()
580 DWORD GetUnwindInfoSize()
582 return GetBlobSize();
585 virtual ZapNodeType GetType()
587 return ZapNodeType_UnwindDataAndGCInfo;
590 virtual DWORD GetSize()
592 return ZapUnwindData::GetSize() + m_cbGCInfo;
595 virtual void Save(ZapWriter * pZapWriter)
597 ZapUnwindData::Save(pZapWriter);
599 pZapWriter->Write(GetGCInfo(), GetGCInfoSize());
602 static ZapGCInfo * NewGCInfo(ZapWriter * pWriter, PVOID pGCInfo, SIZE_T cbGCInfo, PVOID pUnwindInfo, SIZE_T cbUnwindInfo);
611 GCInfoKey(PVOID pGCInfo, SIZE_T cbGCInfo, PVOID pUnwindInfo, SIZE_T cbUnwindInfo)
612 : m_gcInfo(pGCInfo, cbGCInfo), m_unwindInfo(pUnwindInfo, cbUnwindInfo)
616 ZapBlob::SHashKey m_gcInfo;
617 ZapBlob::SHashKey m_unwindInfo;
620 class GCInfoTraits : public NoRemoveSHashTraits< DefaultSHashTraits<ZapGCInfo *> >
623 typedef GCInfoKey key_t;
625 static key_t GetKey(element_t e)
627 LIMITED_METHOD_CONTRACT;
628 return GCInfoKey(e->GetGCInfo(), e->GetGCInfoSize(), e->GetUnwindInfo(), e->GetUnwindInfoSize());
630 static BOOL Equals(key_t k1, key_t k2)
632 LIMITED_METHOD_CONTRACT;
633 return ZapBlob::SHashTraits::Equals(k1.m_gcInfo, k2.m_gcInfo) && ZapBlob::SHashTraits::Equals(k1.m_unwindInfo, k2.m_unwindInfo);
635 static count_t Hash(key_t k)
637 LIMITED_METHOD_CONTRACT;
638 return ZapBlob::SHashTraits::Hash(k.m_gcInfo) ^ ZapBlob::SHashTraits::Hash(k.m_unwindInfo);
641 static const element_t Null() { LIMITED_METHOD_CONTRACT; return NULL; }
642 static bool IsNull(const element_t &e) { LIMITED_METHOD_CONTRACT; return e == NULL; }
645 // Hashtable with all GC info blobs. If two methods have same GC info
646 // we store it just once.
647 SHash< GCInfoTraits > m_blobs;
650 ZapGCInfoTable(ZapImage * pImage)
655 void Preallocate(COUNT_T cbILImage)
657 PREALLOCATE_HASHTABLE(ZapGCInfoTable::m_blobs, 0.0021, cbILImage);
660 // Returns interned instance of the GC info blob
661 ZapGCInfo * GetGCInfo(PVOID pGCInfo, SIZE_T cbGCInfo, PVOID pUnwindInfo, SIZE_T cbUnwindInfo);
668 // Hashtable with all GC info blobs. If two methods have same GC info
669 // we store it just once.
670 SHash< NoRemoveSHashTraits < ZapBlob::SHashTraits > > m_blobs;
673 ZapGCInfoTable(ZapImage * pImage)
678 void Preallocate(COUNT_T cbILImage)
680 PREALLOCATE_HASHTABLE(ZapGCInfoTable::m_blobs, 0.0021, cbILImage);
683 // Returns interned instance of the GC info blob
684 ZapGCInfo * GetGCInfo(PVOID pBlob, SIZE_T cbBlob);
688 //---------------------------------------------------------------------------------------
690 // Zapping of debug info for native code
692 class ZapDebugInfoTable : public ZapNode
699 // Hashtable with all debug info blobs. If two methods have same debug info
700 // we store it just once.
701 SHash< NoRemoveSHashTraits < ZapBlob::SHashTraits > > m_blobs;
703 class LabelledEntry : public ZapNode
706 LabelledEntry * m_pNext;
707 ZapMethodHeader * m_pMethod;
709 LabelledEntry(ZapMethodHeader * pMethod)
714 virtual DWORD GetSize()
716 return sizeof(CORCOMPILE_DEBUG_LABELLED_ENTRY);
719 virtual UINT GetAlignment()
721 return sizeof(DWORD);
724 virtual ZapNodeType GetType()
726 return ZapNodeType_DebugInfoLabelledEntry;
729 virtual void Save(ZapWriter * pZapWriter);
733 ZapDebugInfoTable(ZapImage * pImage)
738 void Preallocate(COUNT_T cbILImage)
740 PREALLOCATE_HASHTABLE(ZapDebugInfoTable::m_blobs, 0.0024, cbILImage);
743 // Returns interned instance of the debug info blob
744 ZapDebugInfo * GetDebugInfo(PVOID pBlob, SIZE_T cbBlob);
746 void PrepareLayout();
747 void PlaceDebugInfo(ZapMethodHeader * pMethod);
750 virtual DWORD GetSize()
752 return m_nCount * sizeof(CORCOMPILE_DEBUG_RID_ENTRY);
755 virtual UINT GetAlignment()
757 return sizeof(DWORD);
760 virtual ZapNodeType GetType()
762 return ZapNodeType_DebugInfoTable;
765 virtual void Save(ZapWriter * pZapWriter);
768 //---------------------------------------------------------------------------------------
770 // Zapping of IBC profile data collection area
772 class ZapProfileData : public ZapNode
774 ZapMethodHeader * m_pMethod;
775 ZapProfileData * m_pNext;
778 ZapProfileData(ZapMethodHeader * pMethod)
783 void SetNext(ZapProfileData * pNext)
788 virtual DWORD GetSize()
790 return sizeof(CORCOMPILE_METHOD_PROFILE_LIST);
793 virtual UINT GetAlignment()
795 return sizeof(TADDR);
798 virtual ZapNodeType GetType()
800 return ZapNodeType_ProfileData;
803 virtual void Save(ZapWriter * pZapWriter);
806 // Zapping of ExceptionInfoTable
807 // ExceptionInfoTable is a lookup table that has 1 entry for each method with EH information.
808 // The table is sorted by method start address, so binary search is used during runtime to find
809 // the EH info for a given method given a method start address.
810 class ZapExceptionInfoLookupTable : public ZapNode
816 ZapExceptionInfo* m_pExceptionInfo;
817 } ExceptionInfoEntry;
819 SArray<ExceptionInfoEntry> m_exceptionInfoEntries;
822 ZapExceptionInfoLookupTable(ZapImage *pImage);
824 void PlaceExceptionInfoEntry(ZapNode* pCode, ZapExceptionInfo* pExceptionInfo);
826 virtual ZapNodeType GetType()
828 return ZapNodeType_ExceptionInfoTable;
830 virtual UINT GetAlignment()
832 return sizeof(TADDR);
834 virtual DWORD GetSize();
835 virtual void Save(ZapWriter* pZapWriter);
839 class ZapUnwindInfoLookupTable : public ZapNode
843 ZapUnwindInfoLookupTable(ZapVirtualSection * pRuntimeFunctionSection, ZapNode * pCodeSection, DWORD totalCodeSize):
844 m_pRuntimeFunctionSection(pRuntimeFunctionSection), m_pCodeSection(pCodeSection), m_TotalCodeSize(totalCodeSize)
848 COUNT_T GetNumEntries()
850 return m_TotalCodeSize/RUNTIME_FUNCTION_LOOKUP_STRIDE + 1;
852 virtual ZapNodeType GetType()
854 return ZapNodeType_UnwindInfoLookupTable;
856 virtual UINT GetAlignment()
858 return sizeof(DWORD);
860 virtual DWORD GetSize();
861 virtual void Save(ZapWriter* pZapWriter);
864 ZapVirtualSection * m_pRuntimeFunctionSection;
865 ZapNode * m_pCodeSection;
866 DWORD m_TotalCodeSize;
869 class ZapColdCodeMap : public ZapNode
872 ZapColdCodeMap(ZapVirtualSection * pRuntimeFunctionSection):
873 m_pRuntimeFunctionSection (pRuntimeFunctionSection)
877 virtual ZapNodeType GetType()
879 return ZapNodeType_ColdCodeMap;
881 virtual UINT GetAlignment()
883 return sizeof(DWORD);
885 virtual DWORD GetSize();
886 virtual void Save(ZapWriter* pZapWriter);
889 ZapVirtualSection * m_pRuntimeFunctionSection;
893 //---------------------------------------------------------------------------------------
895 // Jump thunk for JIT helper
898 const static PCSTR s_rgHelperNames[] = {
899 #define JITHELPER(code,pfnHelper,sig) #code ,
900 #define DYNAMICJITHELPER(code,pfnHelper,sig) "<dynamic> " #code ,
901 #include <jithelpers.h>
905 class ZapHelperThunk : public ZapNode
910 ZapHelperThunk(DWORD dwHelper)
911 : m_dwHelper(dwHelper)
914 static_assert_no_msg(COUNTOF(s_rgHelperNames) == CORINFO_HELP_COUNT);
915 LOG((LF_ZAP, LL_INFO1000000, "Created ZapHelperThunk for helper %3d (%s)\n",
916 (USHORT)m_dwHelper, s_rgHelperNames[(USHORT)m_dwHelper]));
920 virtual DWORD GetSize();
922 virtual ZapNodeType GetType()
924 return ZapNodeType_HelperThunk;
927 virtual void Save(ZapWriter * pZapWriter);
930 class ZapLazyHelperThunk : public ZapNode
932 CorInfoHelpFunc m_dwHelper;
937 DWORD SaveWorker(ZapWriter * pZapWriter);
940 ZapLazyHelperThunk(CorInfoHelpFunc dwHelper)
941 : m_dwHelper(dwHelper)
945 void Place(ZapImage * pImage);
947 virtual DWORD GetSize();
949 virtual ZapNodeType GetType()
951 return ZapNodeType_LazyHelperThunk;
954 virtual void Save(ZapWriter * pZapWriter);
957 #endif // __ZAPCODE_H__