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#ifndef _DATAIMAGE_H_
8#define _DATAIMAGE_H_
9
10#if defined(FEATURE_PREJIT) && !defined(DACCESS_COMPILE)
11
12// All we really need is to pre-declare the PrecodeType enum, but g++ doesn't
13// support enum pre-declaration, so we need to include the declaration itself.
14/*#include "cgensys.h" // needed to include precode.h*/
15#include "precode.h"
16
17typedef BYTE ZapRelocationType; // IMAGE_REL_XXX enum
18
19// IMAGE_REL_BASED_PTR is architecture specific reloc of virtual address
20#ifdef _TARGET_64BIT_
21#define IMAGE_REL_BASED_PTR IMAGE_REL_BASED_DIR64
22#else // !_TARGET_64BIT_
23#define IMAGE_REL_BASED_PTR IMAGE_REL_BASED_HIGHLOW
24#endif // !_TARGET_64BIT_
25
26// Special NGEN-specific relocation type for relative pointer (used to make NGen relocation section smaller)
27#define IMAGE_REL_BASED_RELPTR 0x7D
28
29class CEEPreloader;
30
31class ZapImage;
32class TypeHandleList;
33
34class ZapNode;
35class ZapStoredStructure;
36
37class ZapHeap;
38void *operator new(size_t size, ZapHeap * pZapHeap);
39void *operator new[](size_t size, ZapHeap * pZapHeap);
40
41class InternedStructureTraits;
42typedef SHash<InternedStructureTraits> InternedStructureHashTable;
43
44struct LookupMapBase;
45class InlineTrackingMap;
46
47class DataImage
48{
49public:
50 //
51 // As items are recorded for saving we note some information about the item
52 // to help guide later heuristics.
53 //
54 enum ItemKind
55 {
56 #define DEFINE_ITEM_KIND(id) id,
57 #include "dataimagesection.h"
58
59 ITEM_COUNT,
60 };
61
62 Module *m_module;
63 CEEPreloader *m_preloader;
64 ZapImage * m_pZapImage;
65
66 struct StructureEntry
67 {
68 const void * ptr;
69 ZapNode * pNode;
70 SSIZE_T offset;
71 };
72
73 class StructureTraits : public NoRemoveSHashTraits< DefaultSHashTraits<StructureEntry> >
74 {
75 public:
76 typedef const void * key_t;
77
78 static key_t GetKey(element_t e)
79 {
80 LIMITED_METHOD_CONTRACT;
81 return e.ptr;
82 }
83 static BOOL Equals(key_t k1, key_t k2)
84 {
85 LIMITED_METHOD_CONTRACT;
86 return (k1 == k2);
87 }
88 static count_t Hash(key_t k)
89 {
90 LIMITED_METHOD_CONTRACT;
91 return (count_t)(size_t)k;
92 }
93
94 static const element_t Null() { LIMITED_METHOD_CONTRACT; StructureEntry e; e.ptr = NULL; return e; }
95 static bool IsNull(const element_t &e) { LIMITED_METHOD_CONTRACT; return e.ptr == NULL; }
96 };
97 typedef SHash<StructureTraits> StructureHashTable;
98
99 StructureHashTable m_structures;
100 const StructureEntry * m_pLastLookup; // Cached result of last lookup
101
102 #define MAINTAIN_SAVE_ORDER (0xFFFFFFFF)
103
104 struct SavedNodeEntry
105 {
106 ZapNode * pNode;
107 DWORD dwAssociatedOrder;
108 };
109
110 // These are added in save order, however after PlaceRemainingStructures they may have been
111 // rearranged based on the class layout order stored in the dwAssociatedOrder field.
112 SArray<SavedNodeEntry> m_structuresInOrder;
113
114 void AddStructureInOrder(ZapNode *pNode, BOOL fMaintainSaveOrder = FALSE);
115
116 struct FixupEntry
117 {
118 ZapRelocationType m_type;
119 DWORD m_offset;
120#ifdef _DEBUG
121 DWORD m_ordinal;
122#endif // _DEBUG
123
124 ZapStoredStructure * m_pLocation;
125 ZapNode * m_pTargetNode;
126 };
127
128 SArray<FixupEntry> m_Fixups;
129 COUNT_T m_iCurrentFixup;
130
131 void AppendFixup(FixupEntry entry)
132 {
133#ifdef _DEBUG
134 static DWORD s_ordinal = 1;
135 entry.m_ordinal = s_ordinal++;
136#endif // _DEBUG
137 m_Fixups.Append(entry);
138 }
139
140 static int __cdecl fixupEntryCmp(const void* a_, const void* b_);
141
142 void FixupSectionRange(SIZE_T offset, ZapNode * pNode);
143 void FixupSectionPtr(SIZE_T offset, ZapNode * pNode);
144 void FixupJumpStubPtr(SIZE_T offset, CorInfoHelpFunc ftnNum);
145
146 void FixupModuleRVAs();
147
148 InternedStructureHashTable * m_pInternedStructures;
149 SetSHash<ZapNode *> m_reusedStructures;
150
151 struct RvaInfoStructure
152 {
153 FieldDesc * pFD;
154 DWORD rva;
155 UINT size;
156 UINT align;
157 };
158
159 SArray<RvaInfoStructure> m_rvaInfoVector;
160
161 static int __cdecl rvaInfoVectorEntryCmp(const void* a_, const void* b_);
162
163 MapSHash<PVOID,PVOID> m_surrogates;
164
165 // Often set while a class is being saved in order to associate
166 // stored structures with the class, and therefore its layout order.
167 // Note that it is a best guess and not always set.
168 MethodTable * m_pCurrentAssociatedMethodTable;
169
170 struct MethodProfilingData
171 {
172 MethodDesc *pMD;
173 DWORD flags;
174 };
175
176 class MethodProfilingDataTraits : public NoRemoveSHashTraits< DefaultSHashTraits<MethodProfilingData> >
177 {
178 public:
179 typedef const MethodDesc * key_t;
180
181 static key_t GetKey(element_t e)
182 {
183 LIMITED_METHOD_CONTRACT;
184 return e.pMD;
185 }
186 static BOOL Equals(key_t k1, key_t k2)
187 {
188 LIMITED_METHOD_CONTRACT;
189 return (k1 == k2);
190 }
191 static count_t Hash(key_t k)
192 {
193 LIMITED_METHOD_CONTRACT;
194 return (count_t)(size_t)k;
195 }
196
197 static const element_t Null() { LIMITED_METHOD_CONTRACT; MethodProfilingData e; e.pMD = NULL; e.flags = 0; return e; }
198 static bool IsNull(const element_t &e) { LIMITED_METHOD_CONTRACT; return e.pMD == NULL; }
199 };
200 typedef SHash<MethodProfilingDataTraits> MethodProfilingDataHashTable;
201
202 MethodProfilingDataHashTable m_methodProfilingData;
203
204 // This is a hashmap from inlinee method to an array of inliner methods
205 // So it can answer question: "where did this method get inlined ?"
206 InlineTrackingMap *m_inlineTrackingMap;
207
208 public:
209 DataImage(Module *module, CEEPreloader *preloader);
210 ~DataImage();
211
212 void Preallocate();
213
214 void PreSave();
215 void PostSave();
216
217 Module *GetModule() { LIMITED_METHOD_CONTRACT; return m_module; }
218
219 DWORD GetMethodProfilingFlags(MethodDesc * pMD);
220 void SetMethodProfilingFlags(MethodDesc * pMD, DWORD flags);
221
222 CEEPreloader *GetPreloader() { LIMITED_METHOD_CONTRACT; return m_preloader; }
223
224 ZapHeap * GetHeap();
225
226 //
227 // Data is stored in the image store in three phases.
228 //
229
230 //
231 // In the first phase, all objects are assigned locations in the
232 // data store. This is done by calling StoreStructure on all
233 // structures which are being stored into the image.
234 //
235 // This would typically done by methods on the objects themselves,
236 // each of which stores itself and any objects it references.
237 // Reference loops must be explicitly tested for using IsStored.
238 // (Each structure can be stored only once.)
239 //
240 // Note that StoreStructure makes no guarantees about layout order.
241 // If you want structures of a particular kind to be laid out in
242 // the order they are saved, use StoreStructureInOrder.
243 //
244
245 inline ZapStoredStructure * StoreStructure(const void *data, SIZE_T size,
246 ItemKind kind,
247 int align = sizeof(TADDR))
248 {
249 return StoreStructureHelper(data, size, kind, align, FALSE);
250 }
251
252 inline ZapStoredStructure * StoreStructureInOrder(const void *data, SIZE_T size,
253 ItemKind kind,
254 int align = sizeof(TADDR))
255 {
256 return StoreStructureHelper(data, size, kind, align, TRUE);
257 }
258
259 ZapStoredStructure * StoreStructureHelper(const void *data, SIZE_T size,
260 ItemKind kind,
261 int align,
262 BOOL fMaintainSaveOrder);
263
264 // Often set while a class is being saved in order to associate
265 // stored structures with the class, and therefore its layout order.
266 // Note that it is a best guess and not always set.
267 inline void BeginAssociatingStoredObjectsWithMethodTable(MethodTable *pMT)
268 {
269 m_pCurrentAssociatedMethodTable = pMT;
270 }
271
272 inline void EndAssociatingStoredObjectsWithMethodTable()
273 {
274 m_pCurrentAssociatedMethodTable = NULL;
275 }
276
277 // Bind pointer to the relative offset in ZapNode
278 void BindPointer(const void *p, ZapNode * pNode, SSIZE_T offset);
279
280 void BindPointer(const void *p, ZapStoredStructure * pNode, SSIZE_T offset)
281 {
282 BindPointer(p, (ZapNode *)pNode, offset);
283 }
284
285 void CopyData(ZapStoredStructure * pNode, const void * p, ULONG size);
286 void CopyDataToOffset(ZapStoredStructure * pNode, ULONG offset, const void * p, ULONG size);
287
288 //
289 // In the second phase, data is arranged in the image by successive calls
290 // to PlaceMappedRange. Items are arranged using pointers to data structures in the
291 // original heap, or by giving a StoredStructure along with the original
292 // mapping.
293 //
294
295 // Concrete mapped ranges are the ones that actually correspond to allocations
296 // of new space within the image. They should be placed first. We do not
297 // necessarily populate the space in the image (i.e. copy the data to the image)
298 // from the concrete range: for example the space associated with a
299 // combo structure gets filled by copying the data from the individual items
300 // that make up the parts of the combo structure.
301 //
302 // These can tolerate placing the same item multiple times
303 // PlaceInternedStructureForAddress allows a different section to be used depending on
304 // whether an interned structure actually had duplicates in this image.
305 //
306 void PlaceStructureForAddress(const void * data, CorCompileSection section);
307 void PlaceInternedStructureForAddress(const void * data, CorCompileSection sectionIfReused, CorCompileSection sectionIfSingleton);
308
309 void FixupPointerField(PVOID p, SSIZE_T offset);
310 void FixupRelativePointerField(PVOID p, SSIZE_T offset);
311
312 template<typename T, typename PT>
313 void FixupPlainOrRelativePointerField(const T *base, const RelativePointer<PT> T::* pPointerFieldMember)
314 {
315 STANDARD_VM_CONTRACT;
316 SSIZE_T offset = (SSIZE_T) &(base->*pPointerFieldMember) - (SSIZE_T) base;
317 FixupRelativePointerField((PVOID)base, offset);
318 }
319
320 template<typename T, typename C, typename PT>
321 void FixupPlainOrRelativePointerField(const T *base, const C T::* pFirstPointerFieldMember, const RelativePointer<PT> C::* pSecondPointerFieldMember)
322 {
323 STANDARD_VM_CONTRACT;
324 const RelativePointer<PT> *ptr = &(base->*pFirstPointerFieldMember.*pSecondPointerFieldMember);
325 SSIZE_T offset = (SSIZE_T) ptr - (SSIZE_T) base;
326 FixupRelativePointerField((PVOID)base, offset);
327 }
328
329 template<typename T, typename PT>
330 void FixupPlainOrRelativePointerField(const T *base, const PlainPointer<PT> T::* pPointerFieldMember)
331 {
332 STANDARD_VM_CONTRACT;
333 SSIZE_T offset = (SSIZE_T) &(base->*pPointerFieldMember) - (SSIZE_T) base;
334 FixupPointerField((PVOID)base, offset);
335 }
336
337 template<typename T, typename C, typename PT>
338 void FixupPlainOrRelativePointerField(const T *base, const C T::* pFirstPointerFieldMember, const PlainPointer<PT> C::* pSecondPointerFieldMember)
339 {
340 STANDARD_VM_CONTRACT;
341 const PlainPointer<PT> *ptr = &(base->*pFirstPointerFieldMember.*pSecondPointerFieldMember);
342 SSIZE_T offset = (SSIZE_T) ptr - (SSIZE_T) base;
343 FixupPointerField((PVOID)base, offset);
344 }
345
346 void FixupField(PVOID p, SSIZE_T offset, PVOID pTarget, SSIZE_T targetOffset = 0, ZapRelocationType type = IMAGE_REL_BASED_PTR);
347
348 template<typename T, typename PT>
349 void FixupPlainOrRelativeField(const T *base, const RelativePointer<PT> T::* pPointerFieldMember, PVOID pTarget, SSIZE_T targetOffset = 0)
350 {
351 STANDARD_VM_CONTRACT;
352 SSIZE_T offset = (SSIZE_T) &(base->*pPointerFieldMember) - (SSIZE_T) base;
353 FixupField((PVOID)base, offset, pTarget, targetOffset, IMAGE_REL_BASED_RELPTR);
354 }
355
356 template<typename T, typename PT>
357 void FixupPlainOrRelativeField(const T *base, const PlainPointer<PT> T::* pPointerFieldMember, PVOID pTarget, SSIZE_T targetOffset = 0)
358 {
359 STANDARD_VM_CONTRACT;
360 SSIZE_T offset = (SSIZE_T) &(base->*pPointerFieldMember) - (SSIZE_T) base;
361 FixupField((PVOID)base, offset, pTarget, targetOffset, IMAGE_REL_BASED_PTR);
362 }
363
364 void FixupFieldToNode(PVOID p, SSIZE_T offset, ZapNode * pTarget, SSIZE_T targetOffset = 0, ZapRelocationType type = IMAGE_REL_BASED_PTR);
365
366 void FixupFieldToNode(PVOID p, SSIZE_T offset, ZapStoredStructure * pTarget, SSIZE_T targetOffset = 0, ZapRelocationType type = IMAGE_REL_BASED_PTR)
367 {
368 return FixupFieldToNode(p, offset, (ZapNode *)pTarget, targetOffset, type);
369 }
370
371 template<typename T, typename PT>
372 void FixupPlainOrRelativeFieldToNode(const T *base, const RelativePointer<PT> T::* pPointerFieldMember, ZapNode * pTarget, SSIZE_T targetOffset = 0)
373 {
374 STANDARD_VM_CONTRACT;
375 SSIZE_T offset = (SSIZE_T) &(base->*pPointerFieldMember) - (SSIZE_T) base;
376 FixupFieldToNode((PVOID)base, offset, pTarget, targetOffset, IMAGE_REL_BASED_RELPTR);
377 }
378
379 template<typename T, typename PT>
380 void FixupPlainOrRelativeFieldToNode(const T *base, const RelativePointer<PT> T::* pPointerFieldMember, ZapStoredStructure * pTarget, SSIZE_T targetOffset = 0)
381 {
382 return FixupPlainOrRelativeFieldToNode(base, pPointerFieldMember, (ZapNode *)pTarget, targetOffset);
383 }
384
385 template<typename T, typename PT>
386 void FixupPlainOrRelativeFieldToNode(const T *base, const PlainPointer<PT> T::* pPointerFieldMember, ZapNode * pTarget, SSIZE_T targetOffset = 0)
387 {
388 STANDARD_VM_CONTRACT;
389 SSIZE_T offset = (SSIZE_T) &(base->*pPointerFieldMember) - (SSIZE_T) base;
390 FixupFieldToNode((PVOID)base, offset, pTarget, targetOffset, IMAGE_REL_BASED_PTR);
391 }
392
393 template<typename T, typename PT>
394 void FixupPlainOrRelativeFieldToNode(const T *base, const PlainPointer<PT> T::* pPointerFieldMember, ZapStoredStructure * pTarget, SSIZE_T targetOffset = 0)
395 {
396 return FixupPlainOrRelativeFieldToNode(base, pPointerFieldMember, (ZapNode *)pTarget, targetOffset);
397 }
398
399 BOOL IsStored(const void *data)
400 { WRAPPER_NO_CONTRACT; return m_structures.LookupPtr(data) != NULL; }
401
402 DWORD GetRVA(const void *data);
403
404 void ZeroField(PVOID p, SSIZE_T offset, SIZE_T size);
405 void *GetImagePointer(ZapStoredStructure * pNode);
406 void *GetImagePointer(PVOID p, SSIZE_T offset = 0);
407 ZapNode * GetNodeForStructure(PVOID p, SSIZE_T * pOffset);
408
409 void ZeroPointerField(PVOID p, SSIZE_T offset)
410 { WRAPPER_NO_CONTRACT; ZeroField(p, offset, sizeof(void*)); }
411
412
413 ZapStoredStructure * StoreInternedStructure(const void *data, ULONG size,
414 ItemKind kind,
415 int align = sizeof(TADDR));
416
417 void NoteReusedStructure(const void *data);
418
419 void StoreRvaInfo(FieldDesc * pFD,
420 DWORD rva,
421 UINT size,
422 UINT align);
423
424 void SaveRvaStructure();
425 void FixupRvaStructure();
426
427 // Surrogates are used to reorganize the data before they are saved. RegisterSurrogate and LookupSurrogate
428 // maintains mapping from the original data to the reorganized data.
429 void RegisterSurrogate(PVOID ptr, PVOID surrogate);
430 PVOID LookupSurrogate(PVOID ptr);
431
432 void PlaceRemainingStructures();
433
434 void FixupRVAs();
435
436 void SetRVAsForFields(IMetaDataEmit * pEmit);
437
438 // Called when data contains a function address. The data store
439 // can return a fixed compiled code address if it is compiling
440 // code for the module.
441 ZapNode * GetCodeAddress(MethodDesc * method);
442
443 // Returns TRUE if the method can be called directly without going through prestub
444 BOOL CanDirectCall(MethodDesc * method, CORINFO_ACCESS_FLAGS accessFlags = CORINFO_ACCESS_ANY);
445
446 // Returns the method fixup info if it has one, NULL if method has no fixup info
447 ZapNode * GetFixupList(MethodDesc * method);
448
449 ZapNode * GetHelperThunk(CorInfoHelpFunc ftnNum);
450
451 // pUniqueId is used to allocate unique cells for cases where we cannot use the shared cell.
452 ZapNode * GetTypeHandleImport(TypeHandle th, PVOID pUniqueId = NULL);
453 ZapNode * GetMethodHandleImport(MethodDesc * pMD);
454 ZapNode * GetFieldHandleImport(FieldDesc * pFD);
455 ZapNode * GetModuleHandleImport(Module * pModule);
456 DWORD GetModuleImportIndex(Module * pModule);
457
458 ZapNode * GetExistingTypeHandleImport(TypeHandle th);
459 ZapNode * GetExistingMethodHandleImport(MethodDesc * pMD);
460 ZapNode * GetExistingFieldHandleImport(FieldDesc * pFD);
461
462 ZapNode * GetVirtualImportThunk(MethodTable * pMT, MethodDesc * pMD, int slotNumber);
463
464 ZapNode * GetGenericSignature(PVOID signature, BOOL fMethod);
465
466 void SavePrecode(PVOID ptr, MethodDesc * pMD, PrecodeType t, ItemKind kind, BOOL fIsPrebound = FALSE);
467
468 void StoreCompressedLayoutMap(LookupMapBase *pMap, ItemKind kind);
469
470 // "Fixup" here means "save the pointer either as a poiter or indirection"
471 void FixupModulePointer(Module * pModule, PVOID p, SSIZE_T offset, ZapRelocationType type);
472 void FixupMethodTablePointer(MethodTable * pMT, PVOID p, SSIZE_T offset, ZapRelocationType type);
473 void FixupTypeHandlePointer(TypeHandle th, PVOID p, SSIZE_T offset, ZapRelocationType type);
474 void FixupMethodDescPointer(MethodDesc * pMD, PVOID p, SSIZE_T offset, ZapRelocationType type);
475 void FixupFieldDescPointer(FieldDesc * pFD, PVOID p, SSIZE_T offset, ZapRelocationType type);
476
477 void FixupModulePointer(PVOID p, FixupPointer<PTR_Module> * ppModule);
478 void FixupMethodTablePointer(PVOID p, FixupPointer<PTR_MethodTable> * ppMT);
479 void FixupTypeHandlePointer(PVOID p, FixupPointer<TypeHandle> * pth);
480 void FixupMethodDescPointer(PVOID p, FixupPointer<PTR_MethodDesc> * ppMD);
481 void FixupFieldDescPointer(PVOID p, FixupPointer<PTR_FieldDesc> * ppFD);
482
483 void FixupModulePointer(PVOID p, RelativeFixupPointer<PTR_Module> * ppModule);
484 void FixupMethodTablePointer(PVOID p, RelativeFixupPointer<PTR_MethodTable> * ppMT);
485 void FixupTypeHandlePointer(PVOID p, RelativeFixupPointer<TypeHandle> * pth);
486 void FixupMethodDescPointer(PVOID p, RelativeFixupPointer<PTR_MethodDesc> * ppMD);
487 void FixupFieldDescPointer(PVOID p, RelativeFixupPointer<PTR_FieldDesc> * ppFD);
488
489 // "HardBind" here means "save a reference using a (relocatable) pointer,
490 // where the object we're referring to lives either in an external hard-bound DLL
491 // or in the image currently being saved"
492 //
493 BOOL CanHardBindToZapModule(Module *targetModule);
494
495 void ReportInlining(CORINFO_METHOD_HANDLE inliner, CORINFO_METHOD_HANDLE inlinee);
496 InlineTrackingMap *GetInlineTrackingMap();
497
498private:
499 BOOL CanEagerBindTo(Module *targetModule, Module *pPreferredZapModule, void *address);
500
501public:
502 // "EagerBind" here means "save a reference using pointer in the image currently being saved
503 // or indirection cell refering to to external DLL
504 BOOL CanEagerBindToTypeHandle(TypeHandle th, BOOL fRequirePrerestore = FALSE, TypeHandleList *pVisited = NULL);
505 BOOL CanEagerBindToMethodTable(MethodTable *pMT, BOOL fRequirePrerestore = FALSE, TypeHandleList *pVisited = NULL);
506 BOOL CanEagerBindToMethodDesc(MethodDesc *pMD, BOOL fRequirePrerestore = FALSE, TypeHandleList *pVisited = NULL);
507 BOOL CanEagerBindToFieldDesc(FieldDesc *pFD, BOOL fRequirePrerestore = FALSE, TypeHandleList *pVisited = NULL);
508 BOOL CanEagerBindToModule(Module *pModule);
509
510 // These also check that the target object doesn't need a restore action
511 // upon reload.
512 BOOL CanPrerestoreEagerBindToTypeHandle(TypeHandle th, TypeHandleList *pVisited);
513 BOOL CanPrerestoreEagerBindToMethodTable(MethodTable *pMT, TypeHandleList *pVisited);
514 BOOL CanPrerestoreEagerBindToMethodDesc(MethodDesc *pMD, TypeHandleList *pVisited);
515
516 void HardBindTypeHandlePointer(PVOID p, SSIZE_T offset);
517
518 // This is obsolete in-place fixup that we should get rid of. For now, it is used for:
519 // - FnPtrTypeDescs. These should not be stored in NGen images at all.
520 // - stubs-as-il signatures. These should use tokens when stored in NGen image.
521 void FixupTypeHandlePointerInPlace(PVOID p, SSIZE_T offset, BOOL fForceFixup = FALSE);
522
523 void BeginRegion(CorInfoRegionKind regionKind);
524 void EndRegion(CorInfoRegionKind regionKind);
525};
526
527#endif // FEATURE_PREJIT && !DACCESS_COMPILE
528
529#endif // _DATAIMAGE_H_
530