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// EnCee.h
6//
7
8//
9// Defines the core VM data structures and methods for support EditAndContinue
10//
11// ======================================================================================
12
13
14#ifndef EnC_H
15#define EnC_H
16
17#include "ceeload.h"
18#include "field.h"
19#include "class.h"
20
21#ifdef EnC_SUPPORTED
22
23class FieldDesc;
24struct EnCAddedField;
25struct EnCAddedStaticField;
26class EnCFieldDesc;
27class EnCEEClassData;
28
29typedef DPTR(EnCAddedField) PTR_EnCAddedField;
30typedef DPTR(EnCAddedStaticField) PTR_EnCAddedStaticField;
31typedef DPTR(EnCFieldDesc) PTR_EnCFieldDesc;
32typedef DPTR(EnCEEClassData) PTR_EnCEEClassData;
33
34//---------------------------------------------------------------------------------------
35//
36// EnCFieldDesc - A field descriptor for fields added by EnC
37//
38// Notes: We need to track some additional data for added fields, since they can't
39// simply be glued onto existing object instances like any other field.
40//
41// For each field added, there is a single instance of this object tied to the type where
42// the field was added.
43//
44class EnCFieldDesc : public FieldDesc
45{
46public:
47 // Initialize just the bare minimum necessary now.
48 // We'll do a proper FieldDesc initialization later when Fixup is called.
49 void Init( mdFieldDef token, BOOL fIsStatic);
50
51 // Compute the address of this field for a specific object
52 void *GetAddress( void *o);
53
54 // Returns true if Fixup still needs to be called
55 BOOL NeedsFixup()
56 {
57 LIMITED_METHOD_DAC_CONTRACT;
58 return m_bNeedsFixup;
59 }
60
61 // Used to properly configure the FieldDesc after it has been added
62 // This may do things like load classes (which can trigger a GC), and so can only be
63 // done after the process has resumed execution.
64 VOID Fixup(mdFieldDef token)
65 {
66 WRAPPER_NO_CONTRACT;
67 EEClass::FixupFieldDescForEnC(GetEnclosingMethodTable(), this, token);
68 m_bNeedsFixup = FALSE;
69 }
70
71 // Gets a pointer to the field's contents (assuming this is a static field) if it's
72 // available or NULL otherwise
73 EnCAddedStaticField *GetStaticFieldData();
74
75 // Gets a pointer to the field's contents (assuming this is a static field) if it's
76 // available or allocates space for it and returns the address to the allocated field
77 // Returns a valid address or throws OOM
78 EnCAddedStaticField * GetOrAllocateStaticFieldData();
79
80
81private:
82 // True if Fixup() has been called on this instance
83 BOOL m_bNeedsFixup;
84
85 // For static fields, pointer to where the field value is held
86 PTR_EnCAddedStaticField m_pStaticFieldData;
87};
88
89// EnCAddedFieldElement
90// A node in the linked list representing fields added to a class with EnC
91typedef DPTR(struct EnCAddedFieldElement) PTR_EnCAddedFieldElement;
92struct EnCAddedFieldElement
93{
94 // Pointer to the next element in the list
95 PTR_EnCAddedFieldElement m_next;
96
97 // Details about this field
98 EnCFieldDesc m_fieldDesc;
99
100 // Initialize this entry.
101 // Basically just sets a couple fields to default values.
102 // We'll have to go back later and call Fixup on the fieldDesc.
103 void Init(mdFieldDef token, BOOL fIsStatic)
104 {
105 WRAPPER_NO_CONTRACT;
106 m_next = NULL;
107 m_fieldDesc.Init(token, fIsStatic);
108 }
109};
110
111//---------------------------------------------------------------------------------------
112//
113// EnCEEClassData - EnC specific information about this class
114//
115class EnCEEClassData
116{
117public:
118#ifndef DACCESS_COMPILE
119 // Initialize all the members
120 // pClass - the EEClass we're tracking EnC data for
121 void Init(MethodTable * pMT)
122 {
123 LIMITED_METHOD_CONTRACT;
124 m_pMT = pMT;
125 m_dwNumAddedInstanceFields = 0;
126 m_dwNumAddedStaticFields = 0;
127 m_pAddedInstanceFields = NULL;
128 m_pAddedStaticFields = NULL;
129 }
130#endif
131
132 // Adds the provided new field to the appropriate linked list and updates the appropriate count
133 void AddField(EnCAddedFieldElement *pAddedField);
134
135 // Get the number of instance fields that have been added to this class.
136 // Since we can only add private fields, these fields can't be seen from any other class but this one.
137 int GetAddedInstanceFields()
138 {
139 SUPPORTS_DAC;
140 return m_dwNumAddedInstanceFields;
141 }
142
143 // Get the number of static fields that have been added to this class.
144 int GetAddedStaticFields()
145 {
146 SUPPORTS_DAC;
147 return m_dwNumAddedStaticFields;
148 }
149
150 // Get the methodtable that this EnC data refers to
151 MethodTable * GetMethodTable()
152 {
153 LIMITED_METHOD_DAC_CONTRACT;
154 return m_pMT;
155 }
156
157#ifdef DACCESS_COMPILE
158 void EnumMemoryRegions(CLRDataEnumMemoryFlags flags);
159#endif
160
161private:
162 friend class EEClass;
163 friend class EncApproxFieldDescIterator;
164
165 // The class that this EnC data refers to
166 PTR_MethodTable m_pMT;
167
168 // The number of instance fields that have been added to this class
169 int m_dwNumAddedInstanceFields;
170
171 // The number of static fields that have been added to this class
172 int m_dwNumAddedStaticFields;
173
174 // Linked list of EnCFieldDescs for all the added instance fields
175 PTR_EnCAddedFieldElement m_pAddedInstanceFields;
176
177 // Linked list of EnCFieldDescs for all the added static fields
178 PTR_EnCAddedFieldElement m_pAddedStaticFields;
179};
180
181//---------------------------------------------------------------------------------------
182//
183// EditAndContinueModule - specialization of the Module class which adds EnC support
184//
185// Assumptions:
186//
187// Notes:
188//
189class EditAndContinueModule : public Module
190{
191 VPTR_VTABLE_CLASS(EditAndContinueModule, Module)
192
193 // keep track of the number of changes - this is used to apply a version number
194 // to an updated function. The version number for a function is the overall edit count,
195 // ie the number of times ApplyChanges has been called, not the number of times that
196 // function itself has been edited.
197 int m_applyChangesCount;
198
199 // Holds a table of EnCEEClassData object for classes in this module that have been modified
200 CUnorderedArray<EnCEEClassData*, 5> m_ClassList;
201
202#ifndef DACCESS_COMPILE
203 // Return the minimum permissable address for new IL to be stored at
204 // This can't be less than the current load address because then we'd
205 // have negative RVAs.
206 BYTE *GetEnCBase() { return (BYTE *) GetFile()->GetManagedFileContents(); }
207#endif // DACCESS_COMPILE
208
209private:
210 // Constructor is invoked only by Module::Create
211 friend Module *Module::Create(Assembly *pAssembly, mdToken moduleRef, PEFile *file, AllocMemTracker *pamTracker);
212 EditAndContinueModule(Assembly *pAssembly, mdToken moduleRef, PEFile *file);
213
214protected:
215#ifndef DACCESS_COMPILE
216 // Initialize the module
217 virtual void Initialize(AllocMemTracker *pamTracker);
218#endif
219
220public:
221#ifndef DACCESS_COMPILE
222 // Destruct the module when it's finished being unloaded
223 // Note that due to the loader's allocation mechanism, C++ consturctors and destructors
224 // wouldn't be called.
225 virtual void Destruct();
226#endif
227
228 // Apply an EnC edit
229 HRESULT ApplyEditAndContinue(DWORD cbMetadata,
230 BYTE *pMetadata,
231 DWORD cbIL,
232 BYTE *pIL);
233
234 // Called when a method has been modified (new IL)
235 HRESULT UpdateMethod(MethodDesc *pMethod);
236
237 // Called when a new method has been added to the module's metadata
238 HRESULT AddMethod(mdMethodDef token);
239
240 // Called when a new field has been added to the module's metadata
241 HRESULT AddField(mdFieldDef token);
242
243 // JIT the new version of a function for EnC
244 PCODE JitUpdatedFunction(MethodDesc *pMD, T_CONTEXT *pContext);
245
246 // Remap execution to the latest version of an edited method
247 HRESULT ResumeInUpdatedFunction(MethodDesc *pMD,
248 void *oldDebuggerFuncHandle,
249 SIZE_T newILOffset,
250 T_CONTEXT *pContext);
251
252 // Modify the thread context for EnC remap and resume execution
253 void FixContextAndResume(MethodDesc *pMD,
254 void *oldDebuggerFuncHandle,
255 T_CONTEXT *pContext,
256 EECodeInfo *pOldCodeInfo,
257 EECodeInfo *pNewCodeInfo);
258
259 // Get a pointer to the value of a field added by EnC or return NULL if it doesn't exist
260 PTR_CBYTE ResolveField(OBJECTREF thisPointer,
261 EnCFieldDesc *pFD);
262
263 // Get a pointer to the value of a field added by EnC. Allocates if it doesn't exist, so we'll
264 // return a valid address or throw OOM
265 PTR_CBYTE ResolveOrAllocateField(OBJECTREF thisPointer,
266 EnCFieldDesc * pFD);
267
268
269 // Get class-specific EnC data for a class in this module
270 // Note: For DAC build, getOnly must be TRUE
271 PTR_EnCEEClassData GetEnCEEClassData(MethodTable * pMT, BOOL getOnly = FALSE);
272
273 // Get the number of times edits have been applied to this module
274 int GetApplyChangesCount()
275 {
276 return m_applyChangesCount;
277 }
278
279#ifdef DACCESS_COMPILE
280 virtual void EnumMemoryRegions(CLRDataEnumMemoryFlags flags,
281 bool enumThis);
282#endif
283};
284
285// Information about an instance field value added by EnC
286// When an instance field is added to an object, we will lazily create an EnCAddedField
287// for EACH instance of that object, but there will be a single EnCFieldDesc.
288//
289// Note that if we were concerned about the overhead when there are lots of instances of
290// an object, we could slim this down to just the m_FieldData field by storing a pointer
291// to a growable array of these in the EnCSyncBlockInfo, instead of using a linked list, and
292// have the EnCFieldDesc specify a field index number.
293//
294struct EnCAddedField
295{
296 // This field data hangs off the SyncBlock in a linked list.
297 // This is the pointer to the next field in the list.
298 PTR_EnCAddedField m_pNext;
299
300 // Pointer to the fieldDesc describing which field this refers to
301 PTR_EnCFieldDesc m_pFieldDesc;
302
303 // A dependent handle whose primary object points to the object instance which has been modified,
304 // and whose secondary object points to an EnC helper object containing a reference to the field value.
305 OBJECTHANDLE m_FieldData;
306
307 // Allocates a new EnCAddedField and hook it up to the object
308 static EnCAddedField *Allocate(OBJECTREF thisPointer, EnCFieldDesc *pFD);
309};
310
311// Information about a static field value added by EnC
312// We can't change the MethodTable, so these are hung off the FieldDesc
313// Note that the actual size of this type is variable.
314struct EnCAddedStaticField
315{
316 // Pointer back to the fieldDesc describing which field this refers to
317 // This isn't strictly necessary since our callers always know it, but the overhead
318 // in minimal (per type, not per instance) and this is cleaner and permits an extra sanity check.
319 PTR_EnCFieldDesc m_pFieldDesc;
320
321 // For primitive types, this is the beginning of the actual value.
322 // For reference types and user-defined value types, it's the beginning of a pointer
323 // to the object.
324 // Note that this is intentionally the last field of this structure as it is variably-sized.
325 // NOTE: It looks like we did the same thing for instance fields in EnCAddedField but then simplified
326 // it by always storing just an OBJREF which may point to a boxed value type. I suggest we do the
327 // same here unless we can demonstrate that the extra indirection makes a noticable perf difference
328 // in scenarios which are important for EnC.
329 BYTE m_FieldData;
330
331 // Get a pointer to the contents of this field
332 PTR_CBYTE GetFieldData();
333
334 // Allocate a new instance appropriate for the specified field
335 static EnCAddedStaticField *Allocate(EnCFieldDesc *pFD);
336};
337
338// EnCSyncBlockInfo lives off an object's SyncBlock and contains a lazily-created linked
339// list of the values of all the fields added to the object by EnC
340//
341// Note that much of the logic here would probably belong better in EnCAddedField since it is
342// specific to the implementation there. Perhaps this should ideally just be a container
343// that holds a bunch of EnCAddedFields and can iterate over them and map from EnCFieldDesc
344// to them.
345class EnCSyncBlockInfo
346{
347public:
348 // Initialize the list
349 EnCSyncBlockInfo() :
350 m_pList(PTR_NULL)
351 {
352 }
353
354 // Get a pointer to the data in a specific field on this object or return NULL if it
355 // doesn't exist
356 PTR_CBYTE ResolveField(OBJECTREF thisPointer,
357 EnCFieldDesc * pFieldDesc);
358
359 // Get a pointer to the data in a specific field on this object. We'll allocate if it doesn't already
360 // exist, so we'll only fail on OOM
361 PTR_CBYTE ResolveOrAllocateField(OBJECTREF thisPointer, EnCFieldDesc *pFD);
362
363
364 // Free the data used by this field value. Called after the object instance the
365 // fields belong to is collected.
366 void Cleanup();
367
368private:
369 // Gets the address of an EnC field accounting for its type: valuetype, class or primitive
370 PTR_CBYTE GetEnCFieldAddrFromHelperFieldDesc(FieldDesc * pHelperFieldDesc,
371 OBJECTREF pHelper,
372 EnCFieldDesc * pFD);
373
374 // Pointer to the head of the list
375 PTR_EnCAddedField m_pList;
376};
377
378// The DPTR is actually defined in syncblk.h to make it visible to SyncBlock
379// typedef DPTR(EnCSyncBlockInfo) PTR_EnCSyncBlockInfo;
380
381#endif // !EnC_SUPPORTED
382
383
384//---------------------------------------------------------------------------------------
385//
386// EncApproxFieldDescIterator - Iterates through all fields of a class including ones
387// added by EnC
388//
389// Notes:
390// This is just like ApproxFieldDescIterator, but it also includes EnC fields if
391// EnC is supported.
392// This does not include inherited fields.
393// The order the fields returned here is unspecified.
394//
395// We don't bother maintaining an accurate total and remaining field count like
396// ApproxFieldDescIterator because none of our clients need it. But it would
397// be easy to add this using the data from m_classData
398//
399class EncApproxFieldDescIterator
400{
401public:
402#ifdef EnC_SUPPORTED
403 // Create and initialize the iterator
404 EncApproxFieldDescIterator(MethodTable *pMT, int iteratorType, BOOL fixupEnC);
405
406 // Get the next fieldDesc (either EnC or non-EnC)
407 PTR_FieldDesc Next();
408
409#else
410 // Non-EnC version - simple wrapper
411 EncApproxFieldDescIterator(MethodTable *pMT, int iteratorType, BOOL fixupEnC) :
412 m_nonEnCIter( pMT, iteratorType ) {}
413
414 PTR_FieldDesc Next() { WRAPPER_NO_CONTRACT; return m_nonEnCIter.Next(); }
415#endif // EnC_SUPPORTED
416
417 int GetIteratorType()
418 {
419 LIMITED_METHOD_CONTRACT;
420 SUPPORTS_DAC;
421 return m_nonEnCIter.GetIteratorType();
422 }
423
424private:
425 // The iterator for the non-EnC fields.
426 // We delegate to this for alll non-EnC specific stuff
427 ApproxFieldDescIterator m_nonEnCIter;
428
429#ifdef EnC_SUPPORTED
430 // Return the next available EnC FieldDesc or NULL when done
431 PTR_EnCFieldDesc NextEnC();
432
433 // True if our client wants us to fixup any EnC fieldDescs before handing them back
434 BOOL m_fixupEnC;
435
436 // A count of how many EnC fields have been returned so far
437 int m_encFieldsReturned;
438
439 // The current pointer into one of the EnC field lists when enumerating EnC fields
440 PTR_EnCAddedFieldElement m_pCurrListElem;
441
442 // EnC specific data for the class of interest.
443 // NULL if EnC is disabled or this class doesn't have any EnC data
444 PTR_EnCEEClassData m_encClassData;
445#endif
446};
447
448#endif // #ifndef EnC_H
449