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.
8 /******************************************************************************
16 Wrapper to facilitate multiple JITcompiler support in the COM+ Runtime
18 The ExecutionManager is responsible for managing the RangeSections.
19 Given an IP, it can find the RangeSection which holds that IP.
21 RangeSections contain the JITed codes. Each RangeSection knows the
22 IJitManager which created it.
24 An IJitManager knows about which method bodies live in each RangeSection.
25 It can handle methods of one given CodeType. It can map a method body to
26 a MethodDesc. It knows where the GCInfo about the method lives.
27 Today, we have three IJitManagers viz.
28 1. EEJitManager for JITcompiled code generated by clrjit.dll
29 2. NativeImageJitManager for ngenned code.
30 3. ReadyToRunJitManager for version resiliant ReadyToRun code
32 An ICodeManager knows how to crack a specific format of GCInfo. There is
33 a default format (handled by ExecutionManager::GetDefaultCodeManager())
34 which can be shared by different IJitManagers/IJitCompilers.
36 An ICorJitCompiler knows how to generate code for a method IL, and produce
37 GCInfo in a format which the corresponding IJitManager's ICodeManager
42 +-----------+---------------+---------------+-----------+--- ...
47 +---------------+ +--------+<---- R +---------------+ +--------+<---- R
48 |ICorJitCompiler|<---->|IJitMan |<---- R |ICorJitCompiler|<---->|IJitMan |<---- R
49 +---------------+ +--------+<---- R +---------------+ +--------+<---- R
53 +--------+ R +--------+ R
54 |ICodeMan| |ICodeMan| (RangeSections)
57 ******************************************************************************/
59 #ifndef __CODEMAN_HPP__
61 #define __CODEMAN_HPP__
66 #include "jitinterface.h"
67 #include "debuginfostore.h"
69 #include "pedecoder.h"
73 #if defined(WIN64EXCEPTIONS) && !defined(USE_INDIRECT_CODEHEADER)
74 #error "WIN64EXCEPTIONS requires USE_INDIRECT_CODEHEADER"
75 #endif // WIN64EXCEPTIONS && !USE_INDIRECT_CODEHEADER
78 class ICorJitCompiler;
81 class NativeImageJitManager;
82 class ReadyToRunJitManager;
83 class ExecutionManager;
86 struct EE_ILEXCEPTION;
87 struct EE_ILEXCEPTION_CLAUSE;
91 TADDR pExceptionClauseArray;
92 } EH_CLAUSE_ENUMERATOR;
95 #define ROUND_DOWN_TO_PAGE(x) ( (size_t) (x) & ~((size_t)GetOsPageSize()-1))
96 #define ROUND_UP_TO_PAGE(x) (((size_t) (x) + (GetOsPageSize()-1)) & ~((size_t)GetOsPageSize()-1))
98 enum StubCodeBlockKind : int
100 STUB_CODE_BLOCK_UNKNOWN,
101 STUB_CODE_BLOCK_JUMPSTUB,
102 STUB_CODE_BLOCK_PRECODE,
103 STUB_CODE_BLOCK_DYNAMICHELPER,
104 // Last valid value. Note that the definition is duplicated in debug\daccess\fntableaccess.cpp
105 STUB_CODE_BLOCK_LAST = 0xF,
106 // Placeholders returned by code:GetStubCodeBlockKind
107 STUB_CODE_BLOCK_NOCODE,
108 STUB_CODE_BLOCK_MANAGED,
109 STUB_CODE_BLOCK_STUBLINK,
110 // Placeholdes used by NGen images
111 STUB_CODE_BLOCK_VIRTUAL_METHOD_THUNK,
112 STUB_CODE_BLOCK_EXTERNAL_METHOD_THUNK,
113 // Placeholdes used by ReadyToRun images
114 STUB_CODE_BLOCK_METHOD_CALL_THUNK,
117 //-----------------------------------------------------------------------------
118 // Method header which exists just before the code.
119 // Every IJitManager could have its own format for the header.
120 // Today CodeHeader is used by the EEJitManager.
121 // The GCInfo version is always current GCINFO_VERSION in this header.
123 #ifdef USE_INDIRECT_CODEHEADER
124 typedef DPTR(struct _hpRealCodeHdr) PTR_RealCodeHeader;
125 typedef DPTR(struct _hpCodeHdr) PTR_CodeHeader;
127 #else // USE_INDIRECT_CODEHEADER
128 typedef DPTR(struct _hpCodeHdr) PTR_CodeHeader;
130 #endif // USE_INDIRECT_CODEHEADER
132 #ifdef USE_INDIRECT_CODEHEADER
133 typedef struct _hpRealCodeHdr
134 #else // USE_INDIRECT_CODEHEADER
135 typedef struct _hpCodeHdr
136 #endif // USE_INDIRECT_CODEHEADER
139 PTR_BYTE phdrDebugInfo;
141 // Note - *(&(pCodeHeader->phdrJitEHInfo) - sizeof(size_t))
142 // contains the number of EH clauses, See EEJitManager::allocEHInfo
143 PTR_EE_ILEXCEPTION phdrJitEHInfo;
144 PTR_BYTE phdrJitGCInfo;
146 #if defined(FEATURE_GDBJIT)
147 VOID* pCalledMethods;
150 PTR_MethodDesc phdrMDesc;
152 #ifdef WIN64EXCEPTIONS
154 T_RUNTIME_FUNCTION unwindInfos[0];
155 #endif // WIN64EXCEPTIONS
158 #ifndef USE_INDIRECT_CODEHEADER
160 // Note: that the JITted code follows immediately after the MethodDesc*
162 PTR_BYTE GetDebugInfo()
166 return phdrDebugInfo;
168 PTR_EE_ILEXCEPTION GetEHInfo()
170 return phdrJitEHInfo;
175 return phdrJitGCInfo;
177 PTR_MethodDesc GetMethodDesc()
182 #if defined(FEATURE_GDBJIT)
183 VOID* GetCalledMethods()
186 return pCalledMethods;
189 TADDR GetCodeStartAddress()
192 return dac_cast<TADDR>(dac_cast<PTR_CodeHeader>(this) + 1);
194 StubCodeBlockKind GetStubCodeBlockKind()
197 return (StubCodeBlockKind)dac_cast<TADDR>(phdrMDesc);
199 BOOL IsStubCodeBlock()
202 // Note that it is important for this comparison to be unsigned
203 return dac_cast<TADDR>(phdrMDesc) <= (TADDR)STUB_CODE_BLOCK_LAST;
206 void SetDebugInfo(PTR_BYTE pDI)
210 void SetEHInfo(PTR_EE_ILEXCEPTION pEH)
214 void SetGCInfo(PTR_BYTE pGC)
218 void SetMethodDesc(PTR_MethodDesc pMD)
222 #if defined(FEATURE_GDBJIT)
223 void SetCalledMethods(VOID* pCM)
225 pCalledMethods = pCM;
228 void SetStubCodeBlockKind(StubCodeBlockKind kind)
230 phdrMDesc = (PTR_MethodDesc)kind;
232 #endif // !USE_INDIRECT_CODEHEADER
234 // if we're using the indirect codeheaders then all enumeration is done by the code header
235 #ifndef USE_INDIRECT_CODEHEADER
236 #ifdef DACCESS_COMPILE
237 void EnumMemoryRegions(CLRDataEnumMemoryFlags flags, IJitManager* pJitMan);
238 #endif // DACCESS_COMPILE
239 #endif // USE_INDIRECT_CODEHEADER
240 #ifdef USE_INDIRECT_CODEHEADER
242 #else // USE_INDIRECT_CODEHEADER
244 #endif // USE_INDIRECT_CODEHEADER
246 #ifdef USE_INDIRECT_CODEHEADER
247 typedef struct _hpCodeHdr
249 PTR_RealCodeHeader pRealCodeHeader;
252 PTR_BYTE GetDebugInfo()
255 return pRealCodeHeader->phdrDebugInfo;
257 PTR_EE_ILEXCEPTION GetEHInfo()
259 return pRealCodeHeader->phdrJitEHInfo;
264 return pRealCodeHeader->phdrJitGCInfo;
266 PTR_MethodDesc GetMethodDesc()
269 return pRealCodeHeader->phdrMDesc;
271 #if defined(FEATURE_GDBJIT)
272 VOID* GetCalledMethods()
275 return pRealCodeHeader->pCalledMethods;
278 TADDR GetCodeStartAddress()
281 return dac_cast<PCODE>(dac_cast<PTR_CodeHeader>(this) + 1);
283 StubCodeBlockKind GetStubCodeBlockKind()
286 return (StubCodeBlockKind)dac_cast<TADDR>(pRealCodeHeader);
288 BOOL IsStubCodeBlock()
291 // Note that it is important for this comparison to be unsigned
292 return dac_cast<TADDR>(pRealCodeHeader) <= (TADDR)STUB_CODE_BLOCK_LAST;
295 void SetRealCodeHeader(BYTE* pRCH)
297 pRealCodeHeader = PTR_RealCodeHeader((RealCodeHeader*)pRCH);
300 void SetDebugInfo(PTR_BYTE pDI)
302 pRealCodeHeader->phdrDebugInfo = pDI;
304 void SetEHInfo(PTR_EE_ILEXCEPTION pEH)
306 pRealCodeHeader->phdrJitEHInfo = pEH;
308 void SetGCInfo(PTR_BYTE pGC)
310 pRealCodeHeader->phdrJitGCInfo = pGC;
312 void SetMethodDesc(PTR_MethodDesc pMD)
314 pRealCodeHeader->phdrMDesc = pMD;
316 #if defined(FEATURE_GDBJIT)
317 void SetCalledMethods(VOID* pCM)
319 pRealCodeHeader->pCalledMethods = pCM;
322 void SetStubCodeBlockKind(StubCodeBlockKind kind)
324 pRealCodeHeader = (PTR_RealCodeHeader)kind;
327 #if defined(WIN64EXCEPTIONS)
328 UINT GetNumberOfUnwindInfos()
331 return pRealCodeHeader->nUnwindInfos;
333 void SetNumberOfUnwindInfos(UINT nUnwindInfos)
335 LIMITED_METHOD_CONTRACT;
336 pRealCodeHeader->nUnwindInfos = nUnwindInfos;
338 PTR_RUNTIME_FUNCTION GetUnwindInfo(UINT iUnwindInfo)
341 _ASSERTE(iUnwindInfo < GetNumberOfUnwindInfos());
342 return dac_cast<PTR_RUNTIME_FUNCTION>(
343 PTR_TO_MEMBER_TADDR(RealCodeHeader, pRealCodeHeader, unwindInfos) + iUnwindInfo * sizeof(T_RUNTIME_FUNCTION));
345 #endif // WIN64EXCEPTIONS
347 #ifdef DACCESS_COMPILE
348 void EnumMemoryRegions(CLRDataEnumMemoryFlags flags, IJitManager* pJitMan);
349 #endif // DACCESS_COMPILE
352 #endif // USE_INDIRECT_CODEHEADER
355 //-----------------------------------------------------------------------------
356 // This is a structure used to consolidate the information that we
357 // need we creating new code heaps.
358 // When creating new JumpStubs we have a constarint that the address used
359 // should be in the range [loAddr..hiAddr]
361 struct CodeHeapRequestInfo
364 LoaderAllocator* m_pAllocator;
365 const BYTE * m_loAddr; // lowest address to use to satisfy our request (0 -- don't care)
366 const BYTE * m_hiAddr; // hihest address to use to satisfy our request (0 -- don't care)
367 size_t m_requestSize; // minimum size that must be made available
368 size_t m_reserveSize; // Amount that VirtualAlloc will reserved
369 size_t m_reserveForJumpStubs; // Amount to reserve for jump stubs (won't be allocated)
370 bool m_isDynamicDomain;
371 bool m_isCollectible;
372 bool m_throwOnOutOfMemoryWithinRange;
374 bool IsDynamicDomain() { return m_isDynamicDomain; }
375 void SetDynamicDomain() { m_isDynamicDomain = true; }
377 bool IsCollectible() { return m_isCollectible; }
379 size_t getRequestSize() { return m_requestSize; }
380 void setRequestSize(size_t requestSize) { m_requestSize = requestSize; }
382 size_t getReserveSize() { return m_reserveSize; }
383 void setReserveSize(size_t reserveSize) { m_reserveSize = reserveSize; }
385 size_t getReserveForJumpStubs() { return m_reserveForJumpStubs; }
386 void setReserveForJumpStubs(size_t size) { m_reserveForJumpStubs = size; }
388 bool getThrowOnOutOfMemoryWithinRange() { return m_throwOnOutOfMemoryWithinRange; }
389 void setThrowOnOutOfMemoryWithinRange(bool value) { m_throwOnOutOfMemoryWithinRange = value; }
393 CodeHeapRequestInfo(MethodDesc *pMD)
394 : m_pMD(pMD), m_pAllocator(0),
395 m_loAddr(0), m_hiAddr(0),
396 m_requestSize(0), m_reserveSize(0), m_reserveForJumpStubs(0)
397 { WRAPPER_NO_CONTRACT; Init(); }
399 CodeHeapRequestInfo(MethodDesc *pMD, LoaderAllocator* pAllocator,
400 BYTE * loAddr, BYTE * hiAddr)
401 : m_pMD(pMD), m_pAllocator(pAllocator),
402 m_loAddr(loAddr), m_hiAddr(hiAddr),
403 m_requestSize(0), m_reserveSize(0), m_reserveForJumpStubs(0)
404 { WRAPPER_NO_CONTRACT; Init(); }
407 //-----------------------------------------------------------------------------
409 // A CodeHeap is the abstraction the IJitManager uses to allocate memory
410 // needed to the jitting of a method.
411 // The CodeHeap works together with the HeapList to manage a contiguous block of memory.
412 // The CodeHeap is a non growable chunk of memory (it can be reserved and
413 // committed on demand).
415 // A CodeHeap is naturally protected from multiple threads by the code heap
416 // critical section - m_pCodeHeapCritSec - so if the implementation of the heap
417 // is only for the code manager, no locking needs to occur.
418 // It's important however that a delete operation on the CodeHeap (if any) happens
419 // via EEJitManager::FreeCodeMemory(HostCodeHeap*, void*)
421 // The heap to be created depends on the MethodDesc that is being compiled.
422 // Standard code uses the LoaderCodeHeap, a heap based on the LoaderHeap.
423 // DynamicMethods - and only those - use a HostCodeHeap, a heap that does
424 // normal Alloc/Free so reclamation can be performed.
426 // The convention is that every heap implementation would have a static create
427 // function that returns a HeapList. The HeapList *must* be properly initialized
428 // on return except for the next pointer
431 typedef VPTR(class CodeHeap) PTR_CodeHeap;
435 VPTR_BASE_VTABLE_CLASS(CodeHeap)
440 // virtual dtor. Clean up heap
441 virtual ~CodeHeap() {}
443 // Alloc the specified numbers of bytes for code. Returns NULL if the request does not fit
444 // Space for header is reserved immediately before. It is not included in size.
445 virtual void* AllocMemForCode_NoThrow(size_t header, size_t size, DWORD alignment, size_t reserveForJumpStubs) = 0;
447 #ifdef DACCESS_COMPILE
448 virtual void EnumMemoryRegions(CLRDataEnumMemoryFlags flags) = 0;
452 friend class EEJitManager;
455 //-----------------------------------------------------------------------------
456 // The HeapList works together with the CodeHeap to manage a contiguous block of memory.
458 // A single HeapList contains code only for a single AppDomain. EEJitManager uses
459 // EEJitManager::DomainCodeHeapList to keep a list of HeapLists for each AppDomain.
461 // The number of code heaps at which we increase the size of new code heaps.
462 #define CODE_HEAP_SIZE_INCREASE_THRESHOLD 5
464 typedef DPTR(struct _HeapList) PTR_HeapList;
466 typedef struct _HeapList
473 TADDR endAddress; // the current end of the used portion of the Heap
475 TADDR mapBase; // "startAddress" rounded down to GetOsPageSize(). pHdrMap is relative to this address
476 PTR_DWORD pHdrMap; // bit array used to find the start of methods
478 size_t maxCodeHeapSize;// Size of the entire contiguous block of memory
479 size_t reserveForJumpStubs; // Amount of memory reserved for jump stubs in this block
481 #if defined(_TARGET_AMD64_)
482 BYTE CLRPersonalityRoutine[JUMP_ALLOCATE_SIZE]; // jump thunk to personality routine
483 #elif defined(_TARGET_ARM64_)
484 UINT32 CLRPersonalityRoutine[JUMP_ALLOCATE_SIZE/sizeof(UINT32)]; // jump thunk to personality routine
487 PTR_HeapList GetNext()
488 { SUPPORTS_DAC; return hpNext; }
490 void SetNext(PTR_HeapList next)
495 //-----------------------------------------------------------------------------
496 // Implementation of the standard CodeHeap.
497 // Use the ExplicitControlLoaderHeap for allocations
498 // (Check the base class above - CodeHeap - for comments on the functions)
500 typedef VPTR(class LoaderCodeHeap) PTR_LoaderCodeHeap;
502 class LoaderCodeHeap : CodeHeap
504 #ifdef DACCESS_COMPILE
505 friend class ClrDataAccess;
508 VPTR_VTABLE_CLASS(LoaderCodeHeap, CodeHeap)
511 ExplicitControlLoaderHeap m_LoaderHeap;
512 SSIZE_T m_cbMinNextPad;
514 LoaderCodeHeap(size_t * pPrivatePCLBytes);
517 static HeapList* CreateCodeHeap(CodeHeapRequestInfo *pInfo, LoaderHeap *pJitMetaHeap);
520 virtual ~LoaderCodeHeap()
525 virtual void* AllocMemForCode_NoThrow(size_t header, size_t size, DWORD alignment, size_t reserveForJumpStubs) DAC_EMPTY_RET(NULL);
527 #ifdef DACCESS_COMPILE
528 virtual void EnumMemoryRegions(CLRDataEnumMemoryFlags flags)
531 m_LoaderHeap.EnumMemoryRegions(flags);
537 // On non X86 platforms, the OS defined UnwindInfo (accessed from RUNTIME_FUNCTION
538 // structures) to support the ability unwind the stack. Unfortunatey the pre-Win8
539 // APIs defined a callback API for publishing this data dynamically that ETW does
540 // not use (and really can't because the walk happens in the kernel). In Win8
541 // new APIs were defined that allow incremental publishing via a table.
543 // UnwindInfoTable is a class that wraps the OS APIs that we use to publish
544 // this table. Its job is to allocate the table, deallocate it when we are
545 // done and allow us to add new entries one at a time (AddToUnwindInfoTable)
547 // Each _rangesection has a UnwindInfoTable's which hold the
548 // RUNTIME_FUNCTION array as well as other bookeeping (the current and maximum
549 // size of the array, and the handle used to publish it to the OS.
551 // Ideally we would just use this new API when it is available, however to mininmize
552 // risk and to make the change perfectly pay-for-play, we us the original mechanism
553 // ALWAYS, and in addition publish via the Table ONLY WHEN ETW JIT events are turned
556 // This class implements a 'catchup' routine that allows us to publish existing JITTed
557 // methods when ETW turns on. Currently this is 'sticky' (once we start publishing
558 // both ways, we do so for the life of the process.
560 typedef DPTR(class UnwindInfoTable) PTR_UnwindInfoTable;
561 class UnwindInfoTable {
563 // All public functions are thread-safe.
565 // These are wrapper functions over the UnwindInfoTable functions that are specific to JIT compile code
566 static void PublishUnwindInfoForMethod(TADDR baseAddress, T_RUNTIME_FUNCTION* unwindInfo, int unwindInfoCount);
567 static void UnpublishUnwindInfoForMethod(TADDR entryPoint);
569 // These are lower level functions that assume you have found the list of UnwindInfoTable entries
570 // These are used by the stublinker and the high-level method functions above
571 static void AddToUnwindInfoTable(UnwindInfoTable** unwindInfoPtr, T_RUNTIME_FUNCTION* data, TADDR rangeStart, TADDR rangeEnd);
572 static void RemoveFromUnwindInfoTable(UnwindInfoTable** unwindInfoPtr, TADDR baseAddress, TADDR entryPoint);
574 // By default this publishing is off, this routine turns it on (and optionally publishes existing methods)
575 static void PublishUnwindInfo(bool publishExisting);
581 UnwindInfoTable(ULONG_PTR rangeStart, ULONG_PTR rangeEnd, ULONG size);
582 static void PublishUnwindInfoForExistingMethods();
585 static Volatile<bool> s_publishingActive; // Publishing to ETW is turned on
586 static class Crst* s_pUnwindInfoTableLock; // lock protects all public UnwindInfoTable functions
588 PVOID hHandle; // OS handle for a published RUNTIME_FUNCTION table
589 ULONG_PTR iRangeStart; // Start of memory described by this table
590 ULONG_PTR iRangeEnd; // End of memory described by this table
591 T_RUNTIME_FUNCTION* pTable; // The actual list of method unwind info, sorted by address
592 ULONG cTableCurCount;
593 ULONG cTableMaxCount;
594 int cDeletedEntries; // Number of slots we removed.
597 #endif // defined(_WIN64)
599 //-----------------------------------------------------------------------------
600 // The ExecutionManager uses RangeSection as the abstraction of a contiguous
601 // address range to track the code heaps.
603 typedef DPTR(struct RangeSection) PTR_RangeSection;
610 PTR_IJitManager pjit; // The owner of this address range
612 #ifndef DACCESS_COMPILE
613 // Volatile because of the list can be walked lock-free
614 Volatile<RangeSection *> pnext; // link rangesections in a sorted list
616 PTR_RangeSection pnext;
619 PTR_RangeSection pLastUsed; // for the head node only: a link to rangesections that was used most recently
621 enum RangeSectionFlags
623 RANGE_SECTION_NONE = 0x0,
624 RANGE_SECTION_COLLECTIBLE = 0x1,
625 RANGE_SECTION_CODEHEAP = 0x2,
626 #ifdef FEATURE_READYTORUN
627 RANGE_SECTION_READYTORUN = 0x4,
635 // PTR_CodeHeap pCodeHeap; // valid if RANGE_SECTION_HEAP is set
636 // PTR_Module pZapModule; // valid if RANGE_SECTION_HEAP is not set
638 TADDR pHeapListOrZapModule;
640 PTR_UnwindInfoTable pUnwindInfoTable; // Points to unwind information for this memory range.
641 #endif // defined(_WIN64)
644 /*****************************************************************************/
646 #ifdef CROSSGEN_COMPILE
647 #define CodeFragmentHeap LoaderHeap
651 // A simple linked-list based allocator to expose code heap as loader heap for allocation of precodes.
652 // The loader heap like interface is necessary to support backout. It is also conveniently used to reduce space overhead
653 // for small blocks that are common for precodes.
655 // Allocating precodes on code heap makes them close to other code, it reduces need for jump stubs and thus chance
656 // that we run into bogus OOM because of not being able to allocate memory in particular memory range.
658 class CodeFragmentHeap : public ILoaderHeapBackout
660 PTR_LoaderAllocator m_pAllocator;
664 DPTR(FreeBlock) m_pNext; // Next block
665 SIZE_T m_dwSize; // Size of this block (includes size of FreeBlock)
667 typedef DPTR(FreeBlock) PTR_FreeBlock;
669 PTR_FreeBlock m_pFreeBlocks;
670 StubCodeBlockKind m_kind;
674 void AddBlock(VOID * pMem, size_t dwSize);
675 void RemoveBlock(FreeBlock ** ppBlock);
678 CodeFragmentHeap(LoaderAllocator * pAllocator, StubCodeBlockKind kind);
679 virtual ~CodeFragmentHeap() {}
681 TaggedMemAllocPtr RealAllocAlignedMem(size_t dwRequestedSize
682 ,unsigned dwAlignment
684 ,__in __in_z const char *szFile
689 virtual void RealBackoutMem(void *pMem
692 , __in __in_z const char *szFile
694 , __in __in_z const char *szAllocFile
699 #ifdef DACCESS_COMPILE
700 void EnumMemoryRegions(enum CLRDataEnumMemoryFlags flags)
707 #endif // CROSSGEN_COMPILE
709 typedef DPTR(class CodeFragmentHeap) PTR_CodeFragmentHeap;
711 //-----------------------------------------------------------------------------
713 // Manages the CodeHeap for some of the RangeSections in the ExecutionManager
715 //-----------------------------------------------------------------------------
719 VPTR_BASE_VTABLE_CLASS(IJitManager)
722 struct MethodRegionInfo
724 TADDR hotStartAddress;
726 TADDR coldStartAddress;
730 #ifndef DACCESS_COMPILE
732 #endif // !DACCESS_COMPILE
734 virtual DWORD GetCodeType() = 0;
736 // Used to read debug info.
737 // 1) Caller passes an allocator which these functions use to allocate memory.
738 // This is b/c the store may need to decompress the information just to figure out the size.
739 // 2) Note that these methods use Uncompressed (Normal) jit data.
740 // Compression is just an implementation detail.
741 // 3) These throw on OOM (exceptional case), and may return a
742 // failing HR if no data is available (not exceptional)
744 virtual BOOL GetBoundariesAndVars(
745 const DebugInfoRequest & request,
746 IN FP_IDS_NEW fpNew, IN void * pNewData,
748 OUT ICorDebugInfo::OffsetMapping **ppMap,
749 OUT ULONG32 * pcVars,
750 OUT ICorDebugInfo::NativeVarInfo **ppVars) = 0;
752 virtual BOOL JitCodeToMethodInfo(
753 RangeSection * pRangeSection,
755 MethodDesc** ppMethodDesc,
756 OUT EECodeInfo * pCodeInfo) = 0;
758 virtual PCODE GetCodeAddressForRelOffset(const METHODTOKEN& MethodToken, DWORD relOffset) = 0;
760 virtual TADDR JitTokenToStartAddress(const METHODTOKEN& MethodToken)=0;
761 virtual void JitTokenToMethodRegionInfo(const METHODTOKEN& MethodToken, MethodRegionInfo *methodRegionInfo) = 0;
762 virtual unsigned InitializeEHEnumeration(const METHODTOKEN& MethodToken, EH_CLAUSE_ENUMERATOR* pEnumState)=0;
763 virtual PTR_EXCEPTION_CLAUSE_TOKEN GetNextEHClause(EH_CLAUSE_ENUMERATOR* pEnumState,
764 EE_ILEXCEPTION_CLAUSE* pEHclause)=0;
765 #ifndef DACCESS_COMPILE
766 virtual TypeHandle ResolveEHClause(EE_ILEXCEPTION_CLAUSE* pEHClause,
768 #endif // #ifndef DACCESS_COMPILE
770 virtual GCInfoToken GetGCInfoToken(const METHODTOKEN& MethodToken)=0;
771 PTR_VOID GetGCInfo(const METHODTOKEN& MethodToken)
773 return GetGCInfoToken(MethodToken).Info;
776 TADDR JitTokenToModuleBase(const METHODTOKEN& MethodToken);
778 #if defined(WIN64EXCEPTIONS)
779 virtual PTR_RUNTIME_FUNCTION LazyGetFunctionEntry(EECodeInfo * pCodeInfo) = 0;
781 // GetFuncletStartAddress returns the starting address of the function or funclet indicated by the EECodeInfo address.
782 virtual TADDR GetFuncletStartAddress(EECodeInfo * pCodeInfo);
784 virtual DWORD GetFuncletStartOffsets(const METHODTOKEN& MethodToken, DWORD* pStartFuncletOffsets, DWORD dwLength) = 0;
786 BOOL IsFunclet(EECodeInfo * pCodeInfo);
787 virtual BOOL IsFilterFunclet(EECodeInfo * pCodeInfo);
788 #endif // WIN64EXCEPTIONS
790 virtual StubCodeBlockKind GetStubCodeBlockKind(RangeSection * pRangeSection, PCODE currentPC) = 0;
792 // DAC-specific virtual functions.
793 // Note that these MUST occur below any other virtual function definitions to ensure that the vtable in
794 // DAC builds is compatible with the non-DAC one so that DAC virtual dispatch will work correctly.
795 #if defined(DACCESS_COMPILE)
796 virtual void EnumMemoryRegions(CLRDataEnumMemoryFlags flags);
797 virtual void EnumMemoryRegionsForMethodDebugInfo(CLRDataEnumMemoryFlags flags, MethodDesc * pMD) = 0;
798 #if defined(WIN64EXCEPTIONS)
799 // Enumerate the memory necessary to retrieve the unwind info for a specific method
800 virtual void EnumMemoryRegionsForMethodUnwindInfo(CLRDataEnumMemoryFlags flags, EECodeInfo * pCodeInfo) = 0;
801 #endif // WIN64EXCEPTIONS
802 #endif // DACCESS_COMPILE
804 #ifndef DACCESS_COMPILE
805 void SetCodeManager(ICodeManager *codeMgr)
807 LIMITED_METHOD_CONTRACT;
809 m_runtimeSupport = codeMgr;
811 #endif // !DACCESS_COMPILE
813 ICodeManager *GetCodeManager()
815 LIMITED_METHOD_DAC_CONTRACT;
816 return m_runtimeSupport;
820 PTR_ICodeManager m_runtimeSupport;
823 //-----------------------------------------------------------------------------
826 typedef VPTR(class HostCodeHeap) PTR_HostCodeHeap;
828 typedef VPTR(class EEJitManager) PTR_EEJitManager;
829 typedef VPTR(class NativeImageJitManager) PTR_NativeImageJitManager;
830 typedef VPTR(class ReadyToRunJitManager) PTR_ReadyToRunJitManager;
832 struct JumpStubBlockHeader
834 JumpStubBlockHeader * m_next;
838 LoaderAllocator* GetLoaderAllocator()
840 _ASSERTE(m_zero == 0);
844 void SetLoaderAllocator(LoaderAllocator * loaderAllocator)
847 m_Allocator = loaderAllocator;
850 HostCodeHeap* GetHostCodeHeap()
853 _ASSERTE(m_zero == -1);
857 void SetHostCodeHeap(HostCodeHeap * hostCodeHeap)
860 m_CodeHeap = hostCodeHeap;
865 HostCodeHeap *m_CodeHeap;
866 LoaderAllocator *m_Allocator;
869 INT64 m_zero; // 0 for normal methods and -1 for LCG methods
873 /*****************************************************************************/
875 class EEJitManager : public IJitManager
877 #ifdef DACCESS_COMPILE
878 friend class ClrDataAccess;
880 friend class CheckDuplicatedStructLayouts;
881 friend class CodeHeapIterator;
883 VPTR_VTABLE_CLASS(EEJitManager, IJitManager)
887 // Failing to load the main JIT is a failure.
888 // If the user requested an altjit and we failed to load an altjit, that is also a failure.
891 LIMITED_METHOD_CONTRACT;
893 return (m_jit != NULL)
895 && (!m_AltJITRequired || (m_alternateJit != NULL))
896 #endif // ALLOW_SXS_JIT
901 BOOL IsMainJitLoaded()
903 LIMITED_METHOD_CONTRACT;
905 return (m_jit != NULL);
908 BOOL IsAltJitLoaded()
910 LIMITED_METHOD_CONTRACT;
912 return (m_alternateJit != NULL);
914 #endif // ALLOW_SXS_JIT
928 if( m_alternateJit != NULL )
930 m_alternateJit->clearCache();
932 #endif // ALLOW_SXS_JIT
935 BOOL IsCacheCleanupRequired()
946 if (m_jit->isCacheCleanupRequired())
951 if( !ret && m_alternateJit != NULL )
953 if (m_alternateJit->isCacheCleanupRequired())
956 #endif // ALLOW_SXS_JIT
961 #if !defined CROSSGEN_COMPILE && !defined DACCESS_COMPILE
964 // No destructor necessary. Only one instance of this class that is destroyed at process shutdown.
966 #endif // !CROSSGEN_COMPILE && !DACCESS_COMPILE
969 virtual DWORD GetCodeType()
971 LIMITED_METHOD_DAC_CONTRACT;
972 return (miManaged | miIL);
975 #ifndef CROSSGEN_COMPILE
976 // Used to read debug info.
977 virtual BOOL GetBoundariesAndVars(
978 const DebugInfoRequest & request,
979 IN FP_IDS_NEW fpNew, IN void * pNewData,
981 OUT ICorDebugInfo::OffsetMapping **ppMap,
982 OUT ULONG32 * pcVars,
983 OUT ICorDebugInfo::NativeVarInfo **ppVars);
985 virtual PCODE GetCodeAddressForRelOffset(const METHODTOKEN& MethodToken, DWORD relOffset);
986 #endif // !CROSSGEN_COMPILE
988 virtual BOOL JitCodeToMethodInfo(RangeSection * pRangeSection,
990 MethodDesc ** ppMethodDesc,
991 EECodeInfo * pCodeInfo);
993 virtual TADDR JitTokenToStartAddress(const METHODTOKEN& MethodToken);
994 virtual void JitTokenToMethodRegionInfo(const METHODTOKEN& MethodToken, MethodRegionInfo *methodRegionInfo);
996 #ifndef CROSSGEN_COMPILE
997 virtual unsigned InitializeEHEnumeration(const METHODTOKEN& MethodToken, EH_CLAUSE_ENUMERATOR* pEnumState);
998 virtual PTR_EXCEPTION_CLAUSE_TOKEN GetNextEHClause(EH_CLAUSE_ENUMERATOR* pEnumState,
999 EE_ILEXCEPTION_CLAUSE* pEHclause);
1000 #ifndef DACCESS_COMPILE
1001 virtual TypeHandle ResolveEHClause(EE_ILEXCEPTION_CLAUSE* pEHClause,
1003 #endif // !DACCESS_COMPILE
1004 GCInfoToken GetGCInfoToken(const METHODTOKEN& MethodToken);
1005 #endif // !CROSSGEN_COMPILE
1006 #if !defined DACCESS_COMPILE && !defined CROSSGEN_COMPILE
1007 void RemoveJitData(CodeHeader * pCHdr, size_t GCinfo_len, size_t EHinfo_len);
1008 void Unload(LoaderAllocator* pAllocator);
1009 void CleanupCodeHeaps();
1013 CodeHeader* allocCode(MethodDesc* pFD, size_t blockSize, size_t reserveForJumpStubs, CorJitAllocMemFlag flag
1014 #ifdef WIN64EXCEPTIONS
1016 , TADDR * pModuleBase
1019 BYTE * allocGCInfo(CodeHeader* pCodeHeader, DWORD blockSize, size_t * pAllocationSize);
1020 EE_ILEXCEPTION* allocEHInfo(CodeHeader* pCodeHeader, unsigned numClauses, size_t * pAllocationSize);
1021 JumpStubBlockHeader* allocJumpStubBlock(MethodDesc* pMD, DWORD numJumps,
1022 BYTE * loAddr, BYTE * hiAddr,
1023 LoaderAllocator *pLoaderAllocator,
1024 bool throwOnOutOfMemoryWithinRange);
1026 void * allocCodeFragmentBlock(size_t blockSize, unsigned alignment, LoaderAllocator *pLoaderAllocator, StubCodeBlockKind kind);
1027 #endif // !DACCESS_COMPILE && !CROSSGEN_COMPILE
1029 static CodeHeader * GetCodeHeader(const METHODTOKEN& MethodToken);
1030 static CodeHeader * GetCodeHeaderFromStartAddress(TADDR methodStartAddress);
1032 #ifndef CROSSGEN_COMPILE
1033 #if defined(WIN64EXCEPTIONS)
1034 // Compute function entry lazily. Do not call directly. Use EECodeInfo::GetFunctionEntry instead.
1035 virtual PTR_RUNTIME_FUNCTION LazyGetFunctionEntry(EECodeInfo * pCodeInfo);
1037 virtual DWORD GetFuncletStartOffsets(const METHODTOKEN& MethodToken, DWORD* pStartFuncletOffsets, DWORD dwLength);
1038 #endif // WIN64EXCEPTIONS
1040 virtual StubCodeBlockKind GetStubCodeBlockKind(RangeSection * pRangeSection, PCODE currentPC);
1042 #if defined(DACCESS_COMPILE)
1043 virtual void EnumMemoryRegions(CLRDataEnumMemoryFlags flags);
1044 virtual void EnumMemoryRegionsForMethodDebugInfo(CLRDataEnumMemoryFlags flags, MethodDesc * pMD);
1045 #endif // DACCESS_COMPILE
1046 #if defined(WIN64EXCEPTIONS)
1047 // Enumerate the memory necessary to retrieve the unwind info for a specific method
1048 virtual void EnumMemoryRegionsForMethodUnwindInfo(CLRDataEnumMemoryFlags flags, EECodeInfo * pCodeInfo)
1050 // We don't need to do explicitly enumerate the memory for unwind information for JITted methods because
1051 // it is stored using the Win64 standard dynamic function table mechanism, and dump generation code knows
1052 // it needs to call our code:OutOfProcessFunctionTableCallback in order to save the function table including
1053 // unwind information at dump generation time (since it's dynamic, it will not be otherwise
1054 // available at debug time).
1056 #endif // WIN64EXCEPTIONS
1057 #endif // !CROSSGEN_COMPILE
1059 #ifndef CROSSGEN_COMPILE
1060 #ifndef DACCESS_COMPILE
1061 // Heap Management functions
1062 void NibbleMapSet(HeapList * pHp, TADDR pCode, BOOL bSet);
1063 #endif // !DACCESS_COMPILE
1065 static TADDR FindMethodCode(RangeSection * pRangeSection, PCODE currentPC);
1066 static TADDR FindMethodCode(PCODE currentPC);
1067 #endif // !CROSSGEN_COMPILE
1069 #if !defined DACCESS_COMPILE && !defined CROSSGEN_COMPILE
1070 void FreeCodeMemory(HostCodeHeap *pCodeHeap, void * codeStart);
1071 void RemoveFromCleanupList(HostCodeHeap *pCodeHeap);
1072 void AddToCleanupList(HostCodeHeap *pCodeHeap);
1073 void DeleteCodeHeap(HeapList *pHeapList);
1074 void RemoveCodeHeapFromDomainList(CodeHeap *pHeap, LoaderAllocator *pAllocator);
1075 #endif // !DACCESS_COMPILE && !CROSSGEN_COMPILE
1078 #ifndef CROSSGEN_COMPILE
1079 struct DomainCodeHeapList {
1080 LoaderAllocator *m_pAllocator;
1081 CDynArray<HeapList *> m_CodeHeapList;
1082 DomainCodeHeapList();
1083 ~DomainCodeHeapList();
1087 #ifndef DACCESS_COMPILE
1088 #ifndef CROSSGEN_COMPILE
1089 HeapList* NewCodeHeap(CodeHeapRequestInfo *pInfo, DomainCodeHeapList *pADHeapList);
1090 bool CanUseCodeHeap(CodeHeapRequestInfo *pInfo, HeapList *pCodeHeap);
1091 void* allocCodeRaw(CodeHeapRequestInfo *pInfo,
1092 size_t header, size_t blockSize, unsigned align,
1093 HeapList ** ppCodeHeap);
1095 DomainCodeHeapList *GetCodeHeapList(CodeHeapRequestInfo *pInfo, LoaderAllocator *pAllocator, BOOL fDynamicOnly = FALSE);
1096 DomainCodeHeapList *CreateCodeHeapList(CodeHeapRequestInfo *pInfo);
1097 LoaderHeap* GetJitMetaHeap(MethodDesc *pMD);
1098 #endif // !CROSSGEN_COMPILE
1100 HeapList * GetCodeHeapList()
1105 #ifndef CROSSGEN_COMPILE
1107 void * allocEHInfoRaw(CodeHeader* pCodeHeader, DWORD blockSize, size_t * pAllocationSize);
1110 #endif // !DACCESS_COMPILE
1112 PTR_HeapList m_pCodeHeap;
1115 Crst m_CodeHeapCritSec;
1117 #if !defined(DACCESS_COMPILE)
1119 class CodeHeapIterator
1121 CrstHolder m_lockHolder;
1122 HeapList *m_pHeapList;
1123 LoaderAllocator *m_pLoaderAllocator;
1124 MethodSectionIterator m_Iterator;
1125 MethodDesc *m_pCurrent;
1128 CodeHeapIterator(LoaderAllocator *pLoaderAllocatorFilter = NULL);
1129 ~CodeHeapIterator();
1132 MethodDesc *GetMethod()
1134 LIMITED_METHOD_CONTRACT;
1138 TADDR GetMethodCode()
1140 LIMITED_METHOD_CONTRACT;
1141 return (TADDR)m_Iterator.GetMethodCode();
1144 #endif // !DACCESS_COMPILE
1147 CORJIT_FLAGS m_CPUCompileFlags;
1149 #if !defined CROSSGEN_COMPILE && !defined DACCESS_COMPILE
1154 inline CORJIT_FLAGS GetCPUCompileFlags()
1156 LIMITED_METHOD_CONTRACT;
1157 return m_CPUCompileFlags;
1161 PTR_HostCodeHeap m_cleanupList;
1162 //When EH Clauses are resolved we need to atomically update the TypeHandle
1163 Crst m_EHClauseCritSec;
1165 #if !defined CROSSGEN_COMPILE
1166 // must hold critical section to access this structure.
1167 CUnorderedArray<DomainCodeHeapList *, 5> m_DomainCodeHeaps;
1168 CUnorderedArray<DomainCodeHeapList *, 5> m_DynamicDomainCodeHeaps;
1171 #ifdef _TARGET_AMD64_
1174 // List of reserved memory blocks to be used for jump stub allocation if no suitable memory block is found
1175 // via the regular mechanism
1177 struct EmergencyJumpStubReserve
1179 EmergencyJumpStubReserve * m_pNext;
1184 EmergencyJumpStubReserve * m_pEmergencyJumpStubReserveList;
1187 BYTE * AllocateFromEmergencyJumpStubReserve(const BYTE * loAddr, const BYTE * hiAddr, SIZE_T * pReserveSize);
1188 VOID EnsureJumpStubReserve(BYTE * pImageBase, SIZE_T imageSize, SIZE_T reserveSize);
1192 ICorJitCompiler * m_jit;
1193 HINSTANCE m_JITCompiler;
1194 #if defined(_TARGET_X86_) || defined(_TARGET_AMD64_)
1195 HINSTANCE m_JITCompilerOther; // Stores the handle of the legacy JIT, if one is loaded.
1198 #ifdef ALLOW_SXS_JIT
1199 //put these at the end so that we don't mess up the offsets in the DAC.
1200 ICorJitCompiler * m_alternateJit;
1201 HINSTANCE m_AltJITCompiler;
1202 bool m_AltJITRequired;
1203 #endif //ALLOW_SXS_JIT
1206 //*****************************************************************************
1208 // This class manages IJitManagers and ICorJitCompilers. It has only static
1209 // members. It should never be constucted.
1211 //*****************************************************************************
1213 class ExecutionManager
1215 friend class CorExternalDataAccess;
1216 friend struct _DacGlobals;
1218 #ifdef DACCESS_COMPILE
1219 friend class ClrDataAccess;
1227 // When this is passed to a function, it must directly acquire a reader lock
1228 // before it may continue
1231 // This means the function need not directly acquire a reader lock; however, it
1232 // may call other functions that may require other reader locks (e.g.,
1233 // ExecutionManager::FindJitMan may be called with ScanNoReaderLock, but
1234 // still calls IJitManager::JitCodeToMethodInfo which acquires its own
1235 // IJitManager reader lock)
1239 // Returns default scan flag for current thread
1240 static ScanFlag GetScanFlags();
1242 // Returns whether currentPC is in managed code. Returns false for jump stubs on WIN64.
1243 static BOOL IsManagedCode(PCODE currentPC);
1245 // Special version with profiler hook
1246 static BOOL IsManagedCode(PCODE currentPC, HostCallPreference hostCallPreference, BOOL *pfFailedReaderLock);
1248 // Returns true if currentPC is ready to run codegen
1249 static BOOL IsReadyToRunCode(PCODE currentPC);
1251 // Returns method's start address for a given PC
1252 static PCODE GetCodeStartAddress(PCODE currentPC);
1254 static NativeCodeVersion GetNativeCodeVersion(PCODE currentPC);
1256 // Returns methodDesc for given PC
1257 static MethodDesc * GetCodeMethodDesc(PCODE currentPC);
1259 static IJitManager* FindJitMan(PCODE currentPC)
1267 RangeSection * pRange = FindCodeRange(currentPC, GetScanFlags());
1268 return (pRange != NULL) ? pRange->pjit : NULL;
1271 static RangeSection * FindCodeRange(PCODE currentPC, ScanFlag scanFlag);
1273 static BOOL IsCollectibleMethod(const METHODTOKEN& MethodToken);
1275 class ReaderLockHolder
1278 ReaderLockHolder(HostCallPreference hostCallPreference = AllowHostCalls);
1279 ~ReaderLockHolder();
1284 #ifdef _TARGET_64BIT_
1285 static ULONG GetCLRPersonalityRoutineValue()
1287 LIMITED_METHOD_CONTRACT;
1288 static_assert_no_msg(offsetof(HeapList, CLRPersonalityRoutine) ==
1289 (size_t)((ULONG)offsetof(HeapList, CLRPersonalityRoutine)));
1290 return offsetof(HeapList, CLRPersonalityRoutine);
1292 #endif // _TARGET_64BIT_
1294 static EEJitManager * GetEEJitManager()
1296 LIMITED_METHOD_DAC_CONTRACT;
1297 return m_pEEJitManager;
1300 #ifdef FEATURE_PREJIT
1301 static NativeImageJitManager * GetNativeImageJitManager()
1303 LIMITED_METHOD_DAC_CONTRACT;
1304 return m_pNativeImageJitManager;
1308 #ifdef FEATURE_READYTORUN
1309 static ReadyToRunJitManager * GetReadyToRunJitManager()
1311 LIMITED_METHOD_DAC_CONTRACT;
1312 return m_pReadyToRunJitManager;
1316 static void ClearCaches( void );
1317 static BOOL IsCacheCleanupRequired();
1319 static LPCWSTR GetJitName();
1321 static void Unload(LoaderAllocator *pLoaderAllocator);
1323 static void AddCodeRange(TADDR StartRange, TADDR EndRange,
1325 RangeSection::RangeSectionFlags flags,
1328 static void AddNativeImageRange(TADDR StartRange,
1332 static void DeleteRange(TADDR StartRange);
1334 static void CleanupCodeHeaps();
1336 static ICodeManager* GetDefaultCodeManager()
1338 LIMITED_METHOD_CONTRACT;
1339 return (ICodeManager *)m_pDefaultCodeMan;
1342 static PTR_Module FindZapModule(TADDR currentData);
1343 static PTR_Module FindReadyToRunModule(TADDR currentData);
1345 // FindZapModule flavor to be used during GC to find GCRefMap
1346 static PTR_Module FindModuleForGCRefMap(TADDR currentData);
1348 static RangeSection* GetRangeSectionAndPrev(RangeSection *pRS, TADDR addr, RangeSection **ppPrev);
1350 #ifdef DACCESS_COMPILE
1351 static void EnumRangeList(RangeSection* list,
1352 CLRDataEnumMemoryFlags flags);
1353 static void EnumMemoryRegions(CLRDataEnumMemoryFlags flags);
1356 #ifndef DACCESS_COMPILE
1357 static PCODE jumpStub(MethodDesc* pMD,
1361 LoaderAllocator *pLoaderAllocator = NULL,
1362 bool throwOnOutOfMemoryWithinRange = true);
1366 static RangeSection * FindCodeRangeWithLock(PCODE currentPC);
1368 static BOOL IsManagedCodeWithLock(PCODE currentPC);
1369 static BOOL IsManagedCodeWorker(PCODE currentPC);
1371 static RangeSection* GetRangeSection(TADDR addr);
1373 SPTR_DECL(EECodeManager, m_pDefaultCodeMan);
1375 SPTR_DECL(EEJitManager, m_pEEJitManager);
1376 #ifdef FEATURE_PREJIT
1377 SPTR_DECL(NativeImageJitManager, m_pNativeImageJitManager);
1379 #ifdef FEATURE_READYTORUN
1380 SPTR_DECL(ReadyToRunJitManager, m_pReadyToRunJitManager);
1383 static CrstStatic m_JumpStubCrst;
1384 static CrstStatic m_RangeCrst; // Aquire before writing into m_CodeRangeList and m_DataRangeList
1386 // infrastructure to manage readers so we can lock them out and delete domain data
1387 // make ReaderCount volatile because we have order dependency in READER_INCREMENT
1388 #ifndef DACCESS_COMPILE
1389 static Volatile<RangeSection *> m_CodeRangeList;
1390 static Volatile<LONG> m_dwReaderCount;
1391 static Volatile<LONG> m_dwWriterLock;
1393 SPTR_DECL(RangeSection, m_CodeRangeList);
1394 SVAL_DECL(LONG, m_dwReaderCount);
1395 SVAL_DECL(LONG, m_dwWriterLock);
1398 #ifndef DACCESS_COMPILE
1399 class WriterLockHolder
1403 ~WriterLockHolder();
1408 // The LOCK_TAKEN/RELEASED macros need a "pointer" to the lock object to do
1409 // comparisons between takes & releases (and to provide debugging info to the
1410 // developer). Since Inc/Dec Reader/Writer are static, there's no object to
1411 // use. So we just use the pointer to m_dwReaderCount. Note that both
1412 // readers & writers use this same pointer, which follows the general convention
1413 // of other ReaderWriter locks in the EE code base: each reader/writer locking object
1414 // instance protects only 1 piece of data or code. Readers & writers both access the
1415 // same locking object & shared resource, so conceptually they would share the same
1417 static void * GetPtrForLockContract()
1419 return (void *) &m_dwReaderCount;
1421 #endif // defined(_DEBUG)
1423 static void AddRangeHelper(TADDR StartRange,
1426 RangeSection::RangeSectionFlags flags,
1427 TADDR pHeapListOrZapModule);
1428 static void DeleteRangeHelper(RangeSection** ppRangeList,
1431 #ifndef DACCESS_COMPILE
1432 static PCODE getNextJumpStub(MethodDesc* pMD,
1434 BYTE * loAddr, BYTE * hiAddr,
1435 LoaderAllocator *pLoaderAllocator,
1436 bool throwOnOutOfMemoryWithinRange);
1440 // ***************************************************************************
1441 // Hashtable for JumpStubs for jitted code
1443 struct JumpStubEntry {
1448 class JumpStubTraits : public DefaultSHashTraits<JumpStubEntry>
1451 typedef PCODE key_t;
1453 static key_t GetKey(element_t e)
1455 LIMITED_METHOD_CONTRACT;
1458 static BOOL Equals(key_t k1, key_t k2)
1460 LIMITED_METHOD_CONTRACT;
1463 static count_t Hash(key_t k)
1465 LIMITED_METHOD_CONTRACT;
1467 return (count_t) ((size_t) k ^ ((size_t) k >> 32));
1469 return (count_t)(size_t)k;
1473 static const element_t Null() { LIMITED_METHOD_CONTRACT; JumpStubEntry e; e.m_target = NULL; e.m_jumpStub = NULL; return e; }
1474 static bool IsNull(const element_t &e) { LIMITED_METHOD_CONTRACT; return e.m_target == NULL; }
1475 static const element_t Deleted() { LIMITED_METHOD_CONTRACT; JumpStubEntry e; e.m_target = (PCODE)-1; e.m_jumpStub = NULL; return e; }
1476 static bool IsDeleted(const element_t &e) { LIMITED_METHOD_CONTRACT; return e.m_target == (PCODE)-1; }
1478 typedef SHash<JumpStubTraits> JumpStubTable;
1480 static unsigned m_normal_JumpStubLookup;
1481 static unsigned m_normal_JumpStubUnique;
1482 static unsigned m_normal_JumpStubBlockAllocCount;
1483 static unsigned m_normal_JumpStubBlockFullCount;
1485 static unsigned m_LCG_JumpStubLookup;
1486 static unsigned m_LCG_JumpStubUnique;
1487 static unsigned m_LCG_JumpStubBlockAllocCount;
1488 static unsigned m_LCG_JumpStubBlockFullCount;
1491 struct JumpStubCache
1496 LIMITED_METHOD_CONTRACT;
1499 JumpStubBlockHeader * m_pBlocks;
1500 JumpStubTable m_Table;
1504 inline CodeHeader * EEJitManager::GetCodeHeader(const METHODTOKEN& MethodToken)
1506 LIMITED_METHOD_DAC_CONTRACT;
1507 _ASSERTE(!MethodToken.IsNull());
1508 return dac_cast<PTR_CodeHeader>(MethodToken.m_pCodeHeader);
1511 inline CodeHeader * EEJitManager::GetCodeHeaderFromStartAddress(TADDR methodStartAddress)
1513 LIMITED_METHOD_DAC_CONTRACT;
1514 _ASSERTE(methodStartAddress != NULL);
1515 ARM_ONLY(_ASSERTE((methodStartAddress & THUMB_CODE) == 0));
1516 return dac_cast<PTR_CodeHeader>(methodStartAddress - sizeof(CodeHeader));
1519 inline TADDR EEJitManager::JitTokenToStartAddress(const METHODTOKEN& MethodToken)
1528 CodeHeader * pCH = GetCodeHeader(MethodToken);
1529 return pCH->GetCodeStartAddress();
1532 inline void EEJitManager::JitTokenToMethodRegionInfo(const METHODTOKEN& MethodToken,
1533 MethodRegionInfo * methodRegionInfo)
1540 PRECONDITION(methodRegionInfo != NULL);
1543 methodRegionInfo->hotStartAddress = JitTokenToStartAddress(MethodToken);
1544 methodRegionInfo->hotSize = GetCodeManager()->GetFunctionSize(GetGCInfoToken(MethodToken));
1545 methodRegionInfo->coldStartAddress = 0;
1546 methodRegionInfo->coldSize = 0;
1550 //-----------------------------------------------------------------------------
1551 #ifdef FEATURE_PREJIT
1553 //*****************************************************************************
1554 // Stub JitManager for Managed native.
1556 class NativeImageJitManager : public IJitManager
1558 VPTR_VTABLE_CLASS(NativeImageJitManager, IJitManager)
1561 #ifndef DACCESS_COMPILE
1562 NativeImageJitManager();
1563 #endif // #ifndef DACCESS_COMPILE
1565 virtual DWORD GetCodeType()
1567 LIMITED_METHOD_DAC_CONTRACT;
1568 return (miManaged | miNative);
1571 // Used to read debug info.
1572 virtual BOOL GetBoundariesAndVars(
1573 const DebugInfoRequest & request,
1574 IN FP_IDS_NEW fpNew, IN void * pNewData,
1575 OUT ULONG32 * pcMap,
1576 OUT ICorDebugInfo::OffsetMapping **ppMap,
1577 OUT ULONG32 * pcVars,
1578 OUT ICorDebugInfo::NativeVarInfo **ppVars);
1580 virtual BOOL JitCodeToMethodInfo(RangeSection * pRangeSection,
1582 MethodDesc ** ppMethodDesc,
1583 EECodeInfo * pCodeInfo);
1585 virtual PCODE GetCodeAddressForRelOffset(const METHODTOKEN& MethodToken, DWORD relOffset);
1587 static PTR_Module JitTokenToZapModule(const METHODTOKEN& MethodToken);
1588 virtual TADDR JitTokenToStartAddress(const METHODTOKEN& MethodToken);
1589 virtual void JitTokenToMethodRegionInfo(const METHODTOKEN& MethodToken, MethodRegionInfo * methodRegionInfo);
1591 virtual unsigned InitializeEHEnumeration(const METHODTOKEN& MethodToken, EH_CLAUSE_ENUMERATOR* pEnumState);
1593 virtual PTR_EXCEPTION_CLAUSE_TOKEN GetNextEHClause(EH_CLAUSE_ENUMERATOR* pEnumState,
1594 EE_ILEXCEPTION_CLAUSE* pEHclause);
1596 #ifndef DACCESS_COMPILE
1597 virtual TypeHandle ResolveEHClause(EE_ILEXCEPTION_CLAUSE* pEHClause,
1599 #endif // #ifndef DACCESS_COMPILE
1601 virtual GCInfoToken GetGCInfoToken(const METHODTOKEN& MethodToken);
1603 #if defined(WIN64EXCEPTIONS)
1604 virtual PTR_RUNTIME_FUNCTION LazyGetFunctionEntry(EECodeInfo * pCodeInfo);
1606 virtual TADDR GetFuncletStartAddress(EECodeInfo * pCodeInfo);
1607 virtual DWORD GetFuncletStartOffsets(const METHODTOKEN& MethodToken, DWORD* pStartFuncletOffsets, DWORD dwLength);
1608 virtual BOOL IsFilterFunclet(EECodeInfo * pCodeInfo);
1609 #endif // WIN64EXCEPTIONS
1611 virtual StubCodeBlockKind GetStubCodeBlockKind(RangeSection * pRangeSection, PCODE currentPC);
1613 #if defined(DACCESS_COMPILE)
1614 virtual void EnumMemoryRegions(CLRDataEnumMemoryFlags flags);
1615 virtual void EnumMemoryRegionsForMethodDebugInfo(CLRDataEnumMemoryFlags flags, MethodDesc * pMD);
1616 #if defined(WIN64EXCEPTIONS)
1617 // Enumerate the memory necessary to retrieve the unwind info for a specific method
1618 virtual void EnumMemoryRegionsForMethodUnwindInfo(CLRDataEnumMemoryFlags flags, EECodeInfo * pCodeInfo);
1619 #endif //WIN64EXCEPTIONS
1620 #endif //DACCESS_COMPILE
1623 inline TADDR NativeImageJitManager::JitTokenToStartAddress(const METHODTOKEN& MethodToken)
1632 return JitTokenToModuleBase(MethodToken) +
1633 RUNTIME_FUNCTION__BeginAddress(dac_cast<PTR_RUNTIME_FUNCTION>(MethodToken.m_pCodeHeader));
1636 #endif // FEATURE_PREJIT
1638 #if defined(FEATURE_PREJIT) || defined(FEATURE_READYTORUN)
1640 class NativeExceptionInfoLookupTable
1643 static DWORD LookupExceptionInfoRVAForMethod(PTR_CORCOMPILE_EXCEPTION_LOOKUP_TABLE pTable,
1644 COUNT_T numLookupEntries,
1645 DWORD methodStartRVA,
1649 class NativeUnwindInfoLookupTable
1652 static int LookupUnwindInfoForMethod(DWORD codeOffset,
1653 PTR_RUNTIME_FUNCTION pRuntimeFunctionTable,
1657 #ifdef FEATURE_PREJIT
1658 static BOOL HasExceptionInfo(NGenLayoutInfo * pNgenLayout, PTR_RUNTIME_FUNCTION pMainRuntimeFunction);
1659 static PTR_MethodDesc GetMethodDesc(NGenLayoutInfo * pNgenLayout, PTR_RUNTIME_FUNCTION pMainRuntimeFunction, TADDR moduleBase);
1662 static DWORD GetMethodDescRVA(NGenLayoutInfo * pNgenLayout, PTR_RUNTIME_FUNCTION pMainRuntimeFunction);
1666 #endif // FEATURE_PREJIT || FEATURE_READYTORUN
1668 #ifdef FEATURE_READYTORUN
1670 class ReadyToRunJitManager : public IJitManager
1672 VPTR_VTABLE_CLASS(ReadyToRunJitManager, IJitManager)
1675 #ifndef DACCESS_COMPILE
1676 ReadyToRunJitManager();
1677 #endif // #ifndef DACCESS_COMPILE
1679 virtual DWORD GetCodeType()
1681 LIMITED_METHOD_DAC_CONTRACT;
1682 return (miManaged | miNative);
1685 // Used to read debug info.
1686 virtual BOOL GetBoundariesAndVars(
1687 const DebugInfoRequest & request,
1688 IN FP_IDS_NEW fpNew, IN void * pNewData,
1689 OUT ULONG32 * pcMap,
1690 OUT ICorDebugInfo::OffsetMapping **ppMap,
1691 OUT ULONG32 * pcVars,
1692 OUT ICorDebugInfo::NativeVarInfo **ppVars);
1694 virtual BOOL JitCodeToMethodInfo(RangeSection * pRangeSection,
1696 MethodDesc** ppMethodDesc,
1697 OUT EECodeInfo * pCodeInfo);
1699 virtual PCODE GetCodeAddressForRelOffset(const METHODTOKEN& MethodToken, DWORD relOffset);
1701 static ReadyToRunInfo * JitTokenToReadyToRunInfo(const METHODTOKEN& MethodToken);
1702 static UINT32 JitTokenToGCInfoVersion(const METHODTOKEN& MethodToken);
1704 static PTR_RUNTIME_FUNCTION JitTokenToRuntimeFunction(const METHODTOKEN& MethodToken);
1706 virtual TADDR JitTokenToStartAddress(const METHODTOKEN& MethodToken);
1707 virtual void JitTokenToMethodRegionInfo(const METHODTOKEN& MethodToken, MethodRegionInfo * methodRegionInfo);
1709 virtual unsigned InitializeEHEnumeration(const METHODTOKEN& MethodToken, EH_CLAUSE_ENUMERATOR* pEnumState);
1711 virtual PTR_EXCEPTION_CLAUSE_TOKEN GetNextEHClause(EH_CLAUSE_ENUMERATOR* pEnumState,
1712 EE_ILEXCEPTION_CLAUSE* pEHclause);
1714 #ifndef DACCESS_COMPILE
1715 virtual TypeHandle ResolveEHClause(EE_ILEXCEPTION_CLAUSE* pEHClause,
1717 #endif // #ifndef DACCESS_COMPILE
1719 virtual GCInfoToken GetGCInfoToken(const METHODTOKEN& MethodToken);
1721 #if defined(WIN64EXCEPTIONS)
1722 virtual PTR_RUNTIME_FUNCTION LazyGetFunctionEntry(EECodeInfo * pCodeInfo);
1724 virtual TADDR GetFuncletStartAddress(EECodeInfo * pCodeInfo);
1725 virtual DWORD GetFuncletStartOffsets(const METHODTOKEN& MethodToken, DWORD* pStartFuncletOffsets, DWORD dwLength);
1726 virtual BOOL IsFilterFunclet(EECodeInfo * pCodeInfo);
1727 #endif // WIN64EXCEPTIONS
1729 virtual StubCodeBlockKind GetStubCodeBlockKind(RangeSection * pRangeSection, PCODE currentPC);
1731 #if defined(DACCESS_COMPILE)
1732 virtual void EnumMemoryRegions(CLRDataEnumMemoryFlags flags);
1733 virtual void EnumMemoryRegionsForMethodDebugInfo(CLRDataEnumMemoryFlags flags, MethodDesc * pMD);
1734 #if defined(WIN64EXCEPTIONS)
1735 // Enumerate the memory necessary to retrieve the unwind info for a specific method
1736 virtual void EnumMemoryRegionsForMethodUnwindInfo(CLRDataEnumMemoryFlags flags, EECodeInfo * pCodeInfo);
1737 #endif //WIN64EXCEPTIONS
1738 #endif //DACCESS_COMPILE
1743 //*****************************************************************************
1744 // EECodeInfo provides information about code at particular address:
1745 // - Start of the method and relative offset
1746 // - GC Info of the method
1749 // EECodeInfo caches information from IJitManager and thus avoids
1750 // quering IJitManager repeatedly for same data.
1754 friend BOOL EEJitManager::JitCodeToMethodInfo(RangeSection * pRangeSection, PCODE currentPC, MethodDesc** ppMethodDesc, EECodeInfo * pCodeInfo);
1755 #ifdef FEATURE_PREJIT
1756 friend BOOL NativeImageJitManager::JitCodeToMethodInfo(RangeSection * pRangeSection, PCODE currentPC, MethodDesc** ppMethodDesc, EECodeInfo * pCodeInfo);
1758 #ifdef FEATURE_READYTORUN
1759 friend BOOL ReadyToRunJitManager::JitCodeToMethodInfo(RangeSection * pRangeSection, PCODE currentPC, MethodDesc** ppMethodDesc, EECodeInfo * pCodeInfo);
1765 EECodeInfo(PCODE codeAddress)
1770 // Explicit initialization
1771 void Init(PCODE codeAddress);
1772 void Init(PCODE codeAddress, ExecutionManager::ScanFlag scanFlag);
1774 TADDR GetSavedMethodCode();
1776 TADDR GetStartAddress();
1780 LIMITED_METHOD_DAC_CONTRACT;
1781 return m_pJM != NULL;
1784 IJitManager* GetJitManager()
1786 LIMITED_METHOD_DAC_CONTRACT;
1787 _ASSERTE(m_pJM != NULL);
1791 ICodeManager* GetCodeManager()
1793 LIMITED_METHOD_DAC_CONTRACT;
1794 return GetJitManager()->GetCodeManager();
1797 const METHODTOKEN& GetMethodToken()
1799 LIMITED_METHOD_DAC_CONTRACT;
1800 return m_methodToken;
1803 // This returns a pointer to the start of an instruction; conceptually, a PINSTR.
1804 TADDR GetCodeAddress()
1806 LIMITED_METHOD_DAC_CONTRACT;
1807 return PCODEToPINSTR(m_codeAddress);
1810 NativeCodeVersion GetNativeCodeVersion();
1812 MethodDesc * GetMethodDesc()
1814 LIMITED_METHOD_DAC_CONTRACT;
1818 DWORD GetRelOffset()
1820 LIMITED_METHOD_DAC_CONTRACT;
1824 GCInfoToken GetGCInfoToken()
1826 WRAPPER_NO_CONTRACT;
1827 return GetJitManager()->GetGCInfoToken(GetMethodToken());
1830 PTR_VOID GetGCInfo()
1832 WRAPPER_NO_CONTRACT;
1833 return GetGCInfoToken().Info;
1836 void GetMethodRegionInfo(IJitManager::MethodRegionInfo *methodRegionInfo)
1838 WRAPPER_NO_CONTRACT;
1839 return GetJitManager()->JitTokenToMethodRegionInfo(GetMethodToken(), methodRegionInfo);
1842 TADDR GetModuleBase()
1844 WRAPPER_NO_CONTRACT;
1845 return GetJitManager()->JitTokenToModuleBase(GetMethodToken());
1848 #ifdef WIN64EXCEPTIONS
1849 PTR_RUNTIME_FUNCTION GetFunctionEntry();
1850 BOOL IsFunclet() { WRAPPER_NO_CONTRACT; return GetJitManager()->IsFunclet(this); }
1851 EECodeInfo GetMainFunctionInfo();
1852 ULONG GetFixedStackSize();
1854 #if defined(_TARGET_AMD64_)
1855 BOOL HasFrameRegister();
1856 #endif // _TARGET_AMD64_
1858 #else // WIN64EXCEPTIONS
1859 ULONG GetFixedStackSize()
1861 WRAPPER_NO_CONTRACT;
1862 return GetCodeManager()->GetFrameSize(GetGCInfoToken());
1864 #endif // WIN64EXCEPTIONS
1866 #if defined(_TARGET_AMD64_)
1867 void GetOffsetsFromUnwindInfo(ULONG* pRSPOffset, ULONG* pRBPOffset);
1869 #if defined(_DEBUG) && defined(HAVE_GCCOVER)
1870 // Find first funclet inside (pvFuncletStart, pvFuncletStart + cbCode)
1871 static LPVOID findNextFunclet (LPVOID pvFuncletStart, SIZE_T cbCode, LPVOID *ppvFuncletEnd);
1872 #endif // _DEBUG && HAVE_GCCOVER
1873 #endif // _TARGET_AMD64_
1876 PCODE m_codeAddress;
1877 METHODTOKEN m_methodToken;
1881 #ifdef WIN64EXCEPTIONS
1882 PTR_RUNTIME_FUNCTION m_pFunctionEntry;
1883 #endif // WIN64EXCEPTIONS
1885 #ifdef _TARGET_AMD64_
1886 // Simple helper to return a pointer to the UNWIND_INFO given the offset to the unwind info.
1887 UNWIND_INFO * GetUnwindInfoHelper(ULONG unwindInfoOffset);
1888 #endif // _TARGET_AMD64_
1891 #include "codeman.inl"
1894 #ifdef FEATURE_PREJIT
1895 class MethodSectionIterator;
1898 // MethodIterator class is used to iterate all the methods in an ngen image.
1899 // It will match and report hot (and cold, if any) sections of a method at the same time.
1900 // GcInfo version is always current
1901 class MethodIterator
1904 enum MethodIteratorOptions
1908 All = Hot | Unprofiled
1912 MethodIteratorOptions methodIteratorOptions;
1914 NGenLayoutInfo * m_pNgenLayout;
1915 BOOL m_fHotMethodsDone;
1916 COUNT_T m_CurrentRuntimeFunctionIndex;
1917 COUNT_T m_CurrentColdRuntimeFunctionIndex;
1919 void Init(PTR_Module pModule, PEDecoder * pPEDecoder, MethodIteratorOptions mio);
1922 MethodIterator(PTR_Module pModule, MethodIteratorOptions mio = All);
1923 MethodIterator(PTR_Module pModule, PEDecoder * pPEDecoder, MethodIteratorOptions mio = All);
1927 PTR_MethodDesc GetMethodDesc();
1928 GCInfoToken GetGCInfoToken();
1929 TADDR GetMethodStartAddress();
1930 TADDR GetMethodColdStartAddress();
1931 ULONG GetHotCodeSize();
1933 PTR_RUNTIME_FUNCTION GetRuntimeFunction();
1935 void GetMethodRegionInfo(IJitManager::MethodRegionInfo *methodRegionInfo);
1937 #endif //FEATURE_PREJIT
1939 void ThrowOutOfMemoryWithinRange();
1941 #endif // !__CODEMAN_HPP__