| 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 |  | 
|---|
| 23 | class FieldDesc; | 
|---|
| 24 | struct EnCAddedField; | 
|---|
| 25 | struct EnCAddedStaticField; | 
|---|
| 26 | class EnCFieldDesc; | 
|---|
| 27 | class EnCEEClassData; | 
|---|
| 28 |  | 
|---|
| 29 | typedef DPTR(EnCAddedField) PTR_EnCAddedField; | 
|---|
| 30 | typedef DPTR(EnCAddedStaticField) PTR_EnCAddedStaticField; | 
|---|
| 31 | typedef DPTR(EnCFieldDesc) PTR_EnCFieldDesc; | 
|---|
| 32 | typedef 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 | // | 
|---|
| 44 | class EnCFieldDesc : public FieldDesc | 
|---|
| 45 | { | 
|---|
| 46 | public: | 
|---|
| 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 |  | 
|---|
| 81 | private: | 
|---|
| 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 | 
|---|
| 91 | typedef DPTR(struct EnCAddedFieldElement) PTR_EnCAddedFieldElement; | 
|---|
| 92 | struct 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 | // | 
|---|
| 115 | class EnCEEClassData | 
|---|
| 116 | { | 
|---|
| 117 | public: | 
|---|
| 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 |  | 
|---|
| 161 | private: | 
|---|
| 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 | // | 
|---|
| 189 | class 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 |  | 
|---|
| 209 | private: | 
|---|
| 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 |  | 
|---|
| 214 | protected: | 
|---|
| 215 | #ifndef DACCESS_COMPILE | 
|---|
| 216 | // Initialize the module | 
|---|
| 217 | virtual void Initialize(AllocMemTracker *pamTracker); | 
|---|
| 218 | #endif | 
|---|
| 219 |  | 
|---|
| 220 | public: | 
|---|
| 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 | // | 
|---|
| 294 | struct 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. | 
|---|
| 314 | struct 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. | 
|---|
| 345 | class EnCSyncBlockInfo | 
|---|
| 346 | { | 
|---|
| 347 | public: | 
|---|
| 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 |  | 
|---|
| 368 | private: | 
|---|
| 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 | // | 
|---|
| 399 | class EncApproxFieldDescIterator | 
|---|
| 400 | { | 
|---|
| 401 | public: | 
|---|
| 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 |  | 
|---|
| 424 | private: | 
|---|
| 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 |  | 
|---|