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
6//
7
8
9#ifndef _DYNAMICMETHOD_H_
10#define _DYNAMICMETHOD_H_
11
12#include "jitinterface.h"
13#include "methodtable.h"
14#include <daccess.h>
15
16//---------------------------------------------------------------------------------------
17//
18// This links together a set of news and release in one object.
19// The idea is to have a predefined size allocated up front and used by different calls to new.
20// All the allocation will be released at the same time releaseing an instance of this class
21// Here is how the object is laid out
22// | ptr_to_next_chunk | size_left_in_chunk | data | ... | data
23// This is not a particularly efficient allocator but it works well for a small number of allocation
24// needed while jitting a method
25//
26class ChunkAllocator
27{
28private:
29 #define CHUNK_SIZE 64
30
31 BYTE *m_pData;
32
33public:
34 ChunkAllocator() : m_pData(NULL) {}
35
36 ~ChunkAllocator();
37 void* New(size_t size);
38 void Delete();
39};
40
41//---------------------------------------------------------------------------------------
42//
43class DynamicResolver
44{
45public:
46 // Keep in sync with dynamicIlGenerator.cs
47 enum SecurityControlFlags
48 {
49 Default = 0,
50 SkipVisibilityChecks = 0x1,
51 RestrictedSkipVisibilityChecks = 0x2,
52 HasCreationContext = 0x4,
53 CanSkipCSEvaluation = 0x8,
54 };
55
56
57 // set up and clean up for jitting
58 virtual void FreeCompileTimeState() = 0;
59 virtual void GetJitContext(SecurityControlFlags * securityControlFlags,
60 TypeHandle *typeOwner) = 0;
61 virtual ChunkAllocator* GetJitMetaHeap() = 0;
62
63 //
64 // code info data
65 virtual BYTE * GetCodeInfo(
66 unsigned * pCodeSize,
67 unsigned * pStackSize,
68 CorInfoOptions * pOptions,
69 unsigned * pEHSize) = 0;
70 virtual SigPointer GetLocalSig() = 0;
71
72 //
73 // jit interface api
74 virtual OBJECTHANDLE ConstructStringLiteral(mdToken metaTok) = 0;
75 virtual BOOL IsValidStringRef(mdToken metaTok) = 0;
76 virtual void ResolveToken(mdToken token, TypeHandle * pTH, MethodDesc ** ppMD, FieldDesc ** ppFD) = 0;
77 virtual SigPointer ResolveSignature(mdToken token) = 0;
78 virtual SigPointer ResolveSignatureForVarArg(mdToken token) = 0;
79 virtual void GetEHInfo(unsigned EHnumber, CORINFO_EH_CLAUSE* clause) = 0;
80
81 virtual MethodDesc * GetDynamicMethod() = 0;
82}; // class DynamicResolver
83
84//---------------------------------------------------------------------------------------
85//
86class StringLiteralEntry;
87
88//---------------------------------------------------------------------------------------
89//
90struct DynamicStringLiteral
91{
92 DynamicStringLiteral * m_pNext;
93 StringLiteralEntry * m_pEntry;
94};
95
96//---------------------------------------------------------------------------------------
97//
98// LCGMethodResolver
99//
100// a jit resolver for managed dynamic methods
101//
102class LCGMethodResolver : public DynamicResolver
103{
104 friend class DynamicMethodDesc;
105 friend class DynamicMethodTable;
106 // review this to see whether the EEJitManageris the only thing to worry about
107 friend class ExecutionManager;
108 friend class EEJitManager;
109 friend class HostCodeHeap;
110 friend struct ExecutionManager::JumpStubCache;
111
112public:
113 void Destroy(BOOL fDomainUnload = FALSE);
114
115 void FreeCompileTimeState();
116 void GetJitContext(SecurityControlFlags * securityControlFlags,
117 TypeHandle * typeOwner);
118 void GetJitContextCoop(SecurityControlFlags * securityControlFlags,
119 TypeHandle * typeOwner);
120 ChunkAllocator* GetJitMetaHeap();
121
122 BYTE* GetCodeInfo(unsigned *pCodeSize, unsigned *pStackSize, CorInfoOptions *pOptions, unsigned* pEHSize);
123 SigPointer GetLocalSig();
124
125 OBJECTHANDLE ConstructStringLiteral(mdToken metaTok);
126 BOOL IsValidStringRef(mdToken metaTok);
127 void ResolveToken(mdToken token, TypeHandle * pTH, MethodDesc ** ppMD, FieldDesc ** ppFD);
128 SigPointer ResolveSignature(mdToken token);
129 SigPointer ResolveSignatureForVarArg(mdToken token);
130 void GetEHInfo(unsigned EHnumber, CORINFO_EH_CLAUSE* clause);
131
132 MethodDesc* GetDynamicMethod() { LIMITED_METHOD_CONTRACT; return m_pDynamicMethod; }
133 OBJECTREF GetManagedResolver();
134 void SetManagedResolver(OBJECTHANDLE obj) { LIMITED_METHOD_CONTRACT; m_managedResolver = obj; }
135 void * GetRecordCodePointer() { LIMITED_METHOD_CONTRACT; return m_recordCodePointer; }
136
137 STRINGREF GetStringLiteral(mdToken token);
138 STRINGREF * GetOrInternString(STRINGREF *pString);
139 void AddToUsedIndCellList(BYTE * indcell);
140
141private:
142 void RecycleIndCells();
143 void Reset();
144
145 struct IndCellList
146 {
147 BYTE * indcell;
148 IndCellList * pNext;
149 };
150
151 DynamicMethodDesc* m_pDynamicMethod;
152 OBJECTHANDLE m_managedResolver;
153 BYTE *m_Code;
154 DWORD m_CodeSize;
155 SigPointer m_LocalSig;
156 unsigned short m_StackSize;
157 CorInfoOptions m_Options;
158 unsigned m_EHSize;
159 DynamicMethodTable *m_DynamicMethodTable;
160 DynamicMethodDesc *m_next;
161 void *m_recordCodePointer;
162 ChunkAllocator m_jitMetaHeap;
163 ChunkAllocator m_jitTempData;
164 DynamicStringLiteral* m_DynamicStringLiterals;
165 IndCellList * m_UsedIndCellList; // list to keep track of all the indirection cells used by the jitted code
166 ExecutionManager::JumpStubCache * m_pJumpStubCache;
167}; // class LCGMethodResolver
168
169//---------------------------------------------------------------------------------------
170//
171// a DynamicMethodTable is used by the light code generation to lazily allocate methods.
172// The methods in this MethodTable are not known up front and their signature is defined
173// at runtime
174//
175class DynamicMethodTable
176{
177public:
178#ifndef DACCESS_COMPILE
179 static void CreateDynamicMethodTable(DynamicMethodTable **ppLocation, Module *pModule, AppDomain *pDomain);
180#endif
181
182private:
183 CrstExplicitInit m_Crst;
184 DynamicMethodDesc *m_DynamicMethodList;
185 MethodTable *m_pMethodTable;
186 Module *m_Module;
187 AppDomain *m_pDomain;
188
189 DynamicMethodTable() {WRAPPER_NO_CONTRACT;}
190
191 class LockHolder : public CrstHolder
192 {
193 public:
194 LockHolder(DynamicMethodTable *pDynMT)
195 : CrstHolder(&pDynMT->m_Crst)
196 {
197 WRAPPER_NO_CONTRACT;
198 }
199 };
200 friend class LockHolder;
201
202#ifndef DACCESS_COMPILE
203 void MakeMethodTable(AllocMemTracker *pamTracker);
204 void AddMethodsToList();
205
206public:
207 void Destroy();
208 DynamicMethodDesc* GetDynamicMethod(BYTE *psig, DWORD sigSize, PTR_CUTF8 name);
209 void LinkMethod(DynamicMethodDesc *pMethod);
210
211#endif
212
213#ifdef _DEBUG
214public:
215 DWORD m_Used;
216#endif
217
218}; // class DynamicMethodTable
219
220
221//---------------------------------------------------------------------------------------
222//
223#define HOST_CODEHEAP_SIZE_ALIGN 64
224
225//---------------------------------------------------------------------------------------
226//
227// Implementation of the CodeHeap for DynamicMethods.
228// This CodeHeap uses the host interface VirtualAlloc/Free and allows
229// for reclamation of generated code
230// (Check the base class - CodeHeap in codeman.h - for comments on the functions)
231//
232class HostCodeHeap : CodeHeap
233{
234#ifdef DACCESS_COMPILE
235 friend class ClrDataAccess;
236#else
237 friend class EEJitManager;
238#endif
239
240 VPTR_VTABLE_CLASS(HostCodeHeap, CodeHeap)
241
242private:
243 // pointer back to jit manager info
244 PTR_HeapList m_pHeapList;
245 PTR_EEJitManager m_pJitManager;
246 // basic allocation data
247 PTR_BYTE m_pBaseAddr;
248 PTR_BYTE m_pLastAvailableCommittedAddr;
249 size_t m_TotalBytesAvailable;
250 size_t m_ApproximateLargestBlock;
251 // Heap ref count
252 DWORD m_AllocationCount;
253
254 // data to track free list and pointers into this heap
255 // - on an used block this struct has got a pointer back to the CodeHeap, size and start of aligned allocation
256 // - on an unused block (free block) this tracks the size of the block and the pointer to the next non contiguos free block
257 struct TrackAllocation {
258 union {
259 HostCodeHeap *pHeap;
260 TrackAllocation *pNext;
261 };
262 size_t size;
263 };
264 TrackAllocation *m_pFreeList;
265
266 // used for cleanup. Keep track of the next potential heap to release. Normally NULL
267 HostCodeHeap *m_pNextHeapToRelease;
268 LoaderAllocator*m_pAllocator;
269
270public:
271 static HeapList* CreateCodeHeap(CodeHeapRequestInfo *pInfo, EEJitManager *pJitManager);
272
273private:
274 HostCodeHeap(EEJitManager *pJitManager);
275 HeapList* InitializeHeapList(CodeHeapRequestInfo *pInfo);
276 TrackAllocation* AllocFromFreeList(size_t header, size_t size, DWORD alignment, size_t reserveForJumpStubs);
277 void AddToFreeList(TrackAllocation *pBlockToInsert);
278
279 TrackAllocation* AllocMemory_NoThrow(size_t header, size_t size, DWORD alignment, size_t reserveForJumpStubs);
280
281public:
282 // Space for header is reserved immediately before. It is not included in size.
283 virtual void* AllocMemForCode_NoThrow(size_t header, size_t size, DWORD alignment, size_t reserveForJumpStubs) DAC_EMPTY_RET(NULL);
284
285 virtual ~HostCodeHeap() DAC_EMPTY();
286
287 LoaderAllocator* GetAllocator() { return m_pAllocator; }
288
289#ifdef DACCESS_COMPILE
290 virtual void EnumMemoryRegions(CLRDataEnumMemoryFlags flags);
291#endif
292
293 static TrackAllocation * GetTrackAllocation(TADDR codeStart);
294 static HostCodeHeap* GetCodeHeap(TADDR codeStart);
295
296 void DestroyCodeHeap();
297
298protected:
299 friend class DynamicMethodDesc;
300 friend class LCGMethodResolver;
301
302 void FreeMemForCode(void * codeStart);
303
304#if defined(FEATURE_JIT_PITCHING)
305public:
306 PTR_EEJitManager GetJitManager() { return m_pJitManager; }
307#endif
308
309}; // class HostCodeHeap
310
311//---------------------------------------------------------------------------------------
312//
313#include "ilstubresolver.h"
314
315inline MethodDesc* GetMethod(CORINFO_METHOD_HANDLE methodHandle)
316{
317 LIMITED_METHOD_CONTRACT;
318 return (MethodDesc*) methodHandle;
319}
320
321#ifndef DACCESS_COMPILE
322
323#define CORINFO_MODULE_HANDLE_TYPE_MASK 1
324
325enum CORINFO_MODULE_HANDLE_TYPES
326{
327 CORINFO_NORMAL_MODULE = 0,
328 CORINFO_DYNAMIC_MODULE,
329};
330
331inline bool IsDynamicScope(CORINFO_MODULE_HANDLE module)
332{
333 LIMITED_METHOD_CONTRACT;
334 return (CORINFO_DYNAMIC_MODULE == (((size_t)module) & CORINFO_MODULE_HANDLE_TYPE_MASK));
335}
336
337inline CORINFO_MODULE_HANDLE MakeDynamicScope(DynamicResolver* pResolver)
338{
339 LIMITED_METHOD_CONTRACT;
340 CONSISTENCY_CHECK(0 == (((size_t)pResolver) & CORINFO_MODULE_HANDLE_TYPE_MASK));
341 return (CORINFO_MODULE_HANDLE)(((size_t)pResolver) | CORINFO_DYNAMIC_MODULE);
342}
343
344inline DynamicResolver* GetDynamicResolver(CORINFO_MODULE_HANDLE module)
345{
346 LIMITED_METHOD_CONTRACT;
347 CONSISTENCY_CHECK(IsDynamicScope(module));
348 return (DynamicResolver*)(((size_t)module) & ~((size_t)CORINFO_MODULE_HANDLE_TYPE_MASK));
349}
350
351inline Module* GetModule(CORINFO_MODULE_HANDLE scope)
352{
353 WRAPPER_NO_CONTRACT;
354
355 if (IsDynamicScope(scope))
356 {
357 return GetDynamicResolver(scope)->GetDynamicMethod()->GetModule();
358 }
359 else
360 {
361 return((Module*)scope);
362 }
363}
364
365inline CORINFO_MODULE_HANDLE GetScopeHandle(Module* module)
366{
367 LIMITED_METHOD_CONTRACT;
368 return(CORINFO_MODULE_HANDLE(module));
369}
370
371inline bool IsDynamicMethodHandle(CORINFO_METHOD_HANDLE method)
372{
373 LIMITED_METHOD_CONTRACT;
374 CONSISTENCY_CHECK(NULL != GetMethod(method));
375 return GetMethod(method)->IsDynamicMethod();
376}
377
378#endif // DACCESS_COMPILE
379
380#endif // _DYNAMICMETHOD_H_
381