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 | // |
26 | class ChunkAllocator |
27 | { |
28 | private: |
29 | #define CHUNK_SIZE 64 |
30 | |
31 | BYTE *m_pData; |
32 | |
33 | public: |
34 | ChunkAllocator() : m_pData(NULL) {} |
35 | |
36 | ~ChunkAllocator(); |
37 | void* New(size_t size); |
38 | void Delete(); |
39 | }; |
40 | |
41 | //--------------------------------------------------------------------------------------- |
42 | // |
43 | class DynamicResolver |
44 | { |
45 | public: |
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 | // |
86 | class StringLiteralEntry; |
87 | |
88 | //--------------------------------------------------------------------------------------- |
89 | // |
90 | struct 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 | // |
102 | class 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 | |
112 | public: |
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 | |
141 | private: |
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 | // |
175 | class DynamicMethodTable |
176 | { |
177 | public: |
178 | #ifndef DACCESS_COMPILE |
179 | static void CreateDynamicMethodTable(DynamicMethodTable **ppLocation, Module *pModule, AppDomain *pDomain); |
180 | #endif |
181 | |
182 | private: |
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 | |
206 | public: |
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 |
214 | public: |
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 | // |
232 | class 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 | |
242 | private: |
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 | |
270 | public: |
271 | static HeapList* CreateCodeHeap(CodeHeapRequestInfo *pInfo, EEJitManager *pJitManager); |
272 | |
273 | private: |
274 | HostCodeHeap(EEJitManager *pJitManager); |
275 | HeapList* InitializeHeapList(CodeHeapRequestInfo *pInfo); |
276 | TrackAllocation* AllocFromFreeList(size_t , size_t size, DWORD alignment, size_t reserveForJumpStubs); |
277 | void AddToFreeList(TrackAllocation *pBlockToInsert); |
278 | |
279 | TrackAllocation* AllocMemory_NoThrow(size_t , size_t size, DWORD alignment, size_t reserveForJumpStubs); |
280 | |
281 | public: |
282 | // Space for header is reserved immediately before. It is not included in size. |
283 | virtual void* AllocMemForCode_NoThrow(size_t , 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 | |
298 | protected: |
299 | friend class DynamicMethodDesc; |
300 | friend class LCGMethodResolver; |
301 | |
302 | void FreeMemForCode(void * codeStart); |
303 | |
304 | #if defined(FEATURE_JIT_PITCHING) |
305 | public: |
306 | PTR_EEJitManager GetJitManager() { return m_pJitManager; } |
307 | #endif |
308 | |
309 | }; // class HostCodeHeap |
310 | |
311 | //--------------------------------------------------------------------------------------- |
312 | // |
313 | #include "ilstubresolver.h" |
314 | |
315 | inline 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 | |
325 | enum CORINFO_MODULE_HANDLE_TYPES |
326 | { |
327 | CORINFO_NORMAL_MODULE = 0, |
328 | CORINFO_DYNAMIC_MODULE, |
329 | }; |
330 | |
331 | inline 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 | |
337 | inline 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 | |
344 | inline 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 | |
351 | inline 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 | |
365 | inline CORINFO_MODULE_HANDLE GetScopeHandle(Module* module) |
366 | { |
367 | LIMITED_METHOD_CONTRACT; |
368 | return(CORINFO_MODULE_HANDLE(module)); |
369 | } |
370 | |
371 | inline 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 | |