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 // ===========================================================================
9 // Handles EditAndContinue support in the EE
10 // ===========================================================================
14 #include "dbginterface.h"
15 #include "dllimport.h"
18 #include "stackwalk.h"
20 #ifdef DACCESS_COMPILE
21 #include "../debug/daccess/gcinterface.dac.h"
22 #endif // DACCESS_COMPILE
26 // can't get this on the helper thread at runtime in ResolveField, so make it static and get when add a field.
28 static int g_BreakOnEnCResolveField = -1;
31 #ifndef DACCESS_COMPILE
34 // Module initialization occurs in two phases: the constructor phase and the Initialize phase.
36 // The constructor phase initializes just enough so that Destruct() can be safely called.
37 // It cannot throw or fail.
39 EditAndContinueModule::EditAndContinueModule(Assembly *pAssembly, mdToken moduleRef, PEFile *file)
40 : Module(pAssembly, moduleRef, file)
50 LOG((LF_ENC,LL_INFO100,"EACM::ctor 0x%x\n", this));
52 m_applyChangesCount = CorDB_DEFAULT_ENC_FUNCTION_VERSION;
55 // Module initialization occurs in two phases: the constructor phase and the Initialize phase.
57 // The Initialize() phase completes the initialization after the constructor has run.
58 // It can throw exceptions but whether it throws or succeeds, it must leave the Module
59 // in a state where Destruct() can be safely called.
62 void EditAndContinueModule::Initialize(AllocMemTracker *pamTracker)
68 INJECT_FAULT(COMPlusThrowOM(););
72 LOG((LF_ENC,LL_INFO100,"EACM::Initialize 0x%x\n", this));
73 Module::Initialize(pamTracker);
76 // Called when the module is being destroyed (eg. AD unload time)
77 void EditAndContinueModule::Destruct()
79 LIMITED_METHOD_CONTRACT;
80 LOG((LF_ENC,LL_EVERYTHING,"EACM::Destruct 0x%x\n", this));
82 // Call the superclass's Destruct method...
86 //---------------------------------------------------------------------------------------
88 // ApplyEditAndContinue - updates this module for an EnC
91 // cbDeltaMD - number of bytes pointed to by pDeltaMD
92 // pDeltaMD - pointer to buffer holding the delta metadata
93 // cbDeltaIL - number of bytes pointed to by pDeltaIL
94 // pDeltaIL - pointer to buffer holding the delta IL
98 // if the edit fails for any reason, at any point in this function,
99 // we are toasted, so return out and IDE will end debug session.
102 HRESULT EditAndContinueModule::ApplyEditAndContinue(
116 // Update the module's EnC version number
117 ++m_applyChangesCount;
119 LOG((LF_ENC, LL_INFO100, "EACM::AEAC:\n"));
122 // Debugging hook to optionally break when this method is called
123 static BOOL shouldBreak = -1;
124 if (shouldBreak == -1)
125 shouldBreak = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_EncApplyChanges);
126 if (shouldBreak > 0) {
127 _ASSERTE(!"EncApplyChanges");
130 // Debugging hook to dump out all edits to dmeta and dil files
131 static BOOL dumpChanges = -1;
133 if (dumpChanges == -1)
135 dumpChanges = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_EncDumpApplyChanges);
137 if (dumpChanges> 0) {
140 fn.Printf(W("ApplyChanges.%d.dmeta"), m_applyChangesCount);
142 ec = _wfopen_s(&fp, fn.GetUnicode(), W("wb"));
143 _ASSERTE(SUCCEEDED(ec));
144 fwrite(pDeltaMD, 1, cbDeltaMD, fp);
146 fn.Printf(W("ApplyChanges.%d.dil"), m_applyChangesCount);
147 ec = _wfopen_s(&fp, fn.GetUnicode(), W("wb"));
148 _ASSERTE(SUCCEEDED(ec));
149 fwrite(pDeltaIL, 1, cbDeltaIL, fp);
155 HENUMInternal enumENC;
157 BYTE *pLocalILMemory = NULL;
158 IMDInternalImport *pMDImport = NULL;
159 IMDInternalImport *pNewMDImport = NULL;
161 CONTRACT_VIOLATION(GCViolation); // SafeComHolder goes to preemptive mode, which will trigger a GC
162 SafeComHolder<IMDInternalImportENC> pIMDInternalImportENC;
163 SafeComHolder<IMetaDataEmit> pEmitter;
165 // Apply the changes. Note that ApplyEditAndContinue() requires read/write metadata. If the metadata is
166 // not already RW, then ApplyEditAndContinue() will perform the conversion, invalidate the current
167 // metadata importer, and return us a new one. We can't let that happen. Other parts of the system are
168 // already using the current metadata importer, some possibly in preemptive GC mode at this very moment.
169 // Instead, we ensure that the metadata is RW by calling ConvertMDInternalToReadWrite(), which will make
170 // a new importer if necessary and ensure that new accesses to the metadata use that while still managing
171 // the lifetime of the old importer. Therefore, we can be sure that ApplyEditAndContinue() won't need to
172 // make a new importer.
174 // Ensure the metadata is RW.
177 // ConvertMetadataToRWForEnC should only ever be called on EnC capable files.
178 _ASSERTE(IsEditAndContinueCapable()); // this also checks that the file is EnC capable
179 GetFile()->ConvertMetadataToRWForEnC();
181 EX_CATCH_HRESULT(hr);
185 // Grab the current importer.
186 pMDImport = GetMDImport();
188 // Apply the EnC delta to this module's metadata.
189 IfFailGo(pMDImport->ApplyEditAndContinue(pDeltaMD, cbDeltaMD, &pNewMDImport));
191 // The importer should not have changed! We assert that, and back-stop in a retail build just to be sure.
192 if (pNewMDImport != pMDImport)
194 _ASSERTE( !"ApplyEditAndContinue should not have needed to create a new metadata importer!" );
195 IfFailGo(CORDBG_E_ENC_INTERNAL_ERROR);
198 // get the delta interface
199 IfFailGo(pMDImport->QueryInterface(IID_IMDInternalImportENC, (void **)&pIMDInternalImportENC));
201 // get an emitter interface
202 IfFailGo(GetMetaDataPublicInterfaceFromInternal(pMDImport, IID_IMetaDataEmit, (void **)&pEmitter));
204 // Copy the deltaIL into our RVAable IL memory
205 pLocalILMemory = new BYTE[cbDeltaIL];
206 memcpy(pLocalILMemory, pDeltaIL, cbDeltaIL);
208 // Enumerate all of the EnC delta tokens
209 memset(&enumENC, 0, sizeof(HENUMInternal));
210 IfFailGo(pIMDInternalImportENC->EnumDeltaTokensInit(&enumENC));
213 while (pIMDInternalImportENC->EnumNext(&enumENC, &token))
215 STRESS_LOG3(LF_ENC, LL_INFO100, "EACM::AEAC: updated token 0x%x; type 0x%x; rid 0x%x\n", token, TypeFromToken(token), RidFromToken(token));
217 switch (TypeFromToken(token))
221 // MethodDef token - update/add a method
222 LOG((LF_ENC, LL_INFO10000, "EACM::AEAC: Found method 0x%x\n", token));
226 IfFailGo(pMDImport->GetMethodImplProps(token, &dwMethodRVA, &dwMethodFlags));
228 if (dwMethodRVA >= cbDeltaIL)
230 LOG((LF_ENC, LL_INFO10000, "EACM::AEAC: failure RVA of %d with cbDeltaIl %d\n", dwMethodRVA, cbDeltaIL));
231 IfFailGo(E_INVALIDARG);
234 SetDynamicIL(token, (TADDR)(pLocalILMemory + dwMethodRVA), FALSE);
236 // use module to resolve to method
238 pMethod = LookupMethodDef(token);
241 // Method exists already - update it
242 IfFailGo(UpdateMethod(pMethod));
246 // This is a new method token - create a new method
247 IfFailGo(AddMethod(token));
254 // FieldDef token - add a new field
255 LOG((LF_ENC, LL_INFO10000, "EACM::AEAC: Found field 0x%x\n", token));
257 if (LookupFieldDef(token))
259 // Field already exists - just ignore for now
263 // Field is new - add it
264 IfFailGo(AddField(token));
268 EnsureTypeRefCanBeStored(token);
272 EnsureAssemblyRefCanBeStored(token);
278 if (pIMDInternalImportENC)
279 pIMDInternalImportENC->EnumClose(&enumENC);
284 //---------------------------------------------------------------------------------------
286 // UpdateMethod - called when a method has been updated by EnC.
288 // The module's metadata has already been updated. Here we notify the
289 // debugger of the update, and swap the new IL in as the current
290 // version of the method.
293 // pMethod - the method being updated
297 // if the edit fails for any reason, at any point in this function,
298 // we are toasted, so return out and IDE will end debug session.
301 // The CLR must be suspended for debugging.
303 HRESULT EditAndContinueModule::UpdateMethod(MethodDesc *pMethod)
313 // Notify the debugger of the update
314 HRESULT hr = g_pDebugInterface->UpdateFunction(pMethod, m_applyChangesCount);
320 // Notify the JIT that we've got new IL for this method
321 // This will ensure that all new calls to the method will go to the new version.
322 // The runtime does this by never backpatching the methodtable slots in EnC-enabled modules.
323 LOG((LF_ENC, LL_INFO100000, "EACM::UM: Updating function %s to version %d\n", pMethod->m_pszDebugMethodName, m_applyChangesCount));
325 // Reset any flags relevant to the old code
327 // Note that this only works since we've very carefullly made sure that _all_ references
328 // to the Method's code must be to the call/jmp blob immediately in front of the
329 // MethodDesc itself. See MethodDesc::IsEnCMethod()
336 //---------------------------------------------------------------------------------------
338 // AddMethod - called when a new method is added by EnC.
340 // The module's metadata has already been updated. Here we notify the
341 // debugger of the update, and create and add a new MethodDesc to the class.
344 // token - methodDef token for the method being added
348 // if the edit fails for any reason, at any point in this function,
349 // we are toasted, so return out and IDE will end debug session.
352 // The CLR must be suspended for debugging.
354 HRESULT EditAndContinueModule::AddMethod(mdMethodDef token)
364 mdTypeDef parentTypeDef;
365 HRESULT hr = GetMDImport()->GetParentToken(token, &parentTypeDef);
368 LOG((LF_ENC, LL_INFO100, "**Error** EnCModule::AM can't find parent token for method token %p\n", token));
372 // see if the class is loaded yet.
373 MethodTable * pParentType = LookupTypeDef(parentTypeDef).AsMethodTable();
374 if (pParentType == NULL)
376 // Class isn't loaded yet, don't have to modify any existing EE data structures beyond the metadata.
377 // Just notify debugger and return.
378 LOG((LF_ENC, LL_INFO100, "EnCModule::AM class %p not loaded, our work is done\n", parentTypeDef));
379 hr = g_pDebugInterface->UpdateNotYetLoadedFunction(token, this, m_applyChangesCount);
383 // Add the method to the runtime's Class data structures
384 LOG((LF_ENC, LL_INFO100000, "EACM::AM: Adding function %p\n", token));
385 MethodDesc *pMethod = NULL;
386 hr = EEClass::AddMethod(pParentType, token, 0, &pMethod);
390 _ASSERTE(!"Failed to add function");
391 LOG((LF_ENC, LL_INFO100000, "**Error** EACM::AM: Failed to add function %p with hr 0x%x\n", token));
395 // Tell the debugger about the new method so it get's the version number properly
396 hr = g_pDebugInterface->AddFunction(pMethod, m_applyChangesCount);
399 _ASSERTE(!"Failed to add function");
400 LOG((LF_ENC, LL_INFO100000, "**Error** EACM::AF: Failed to add method %p to debugger with hr 0x%x\n", token));
406 //---------------------------------------------------------------------------------------
408 // AddField - called when a new field is added by EnC.
410 // The module's metadata has already been updated. Here we notify the
411 // debugger of the update,
414 // token - fieldDef for the field being added
418 // if the edit fails for any reason, at any point in this function,
419 // we are toasted, so return out and IDE will end debug session.
422 // The CLR must be suspended for debugging.
424 HRESULT EditAndContinueModule::AddField(mdFieldDef token)
434 mdTypeDef parentTypeDef;
435 HRESULT hr = GetMDImport()->GetParentToken(token, &parentTypeDef);
439 LOG((LF_ENC, LL_INFO100, "**Error** EnCModule::AF can't find parent token for field token %p\n", token));
443 // see if the class is loaded yet. If not we don't need to do anything. When this class is
444 // loaded (with the updated metadata), it will have this field like any other normal field.
445 // If the class hasn't been loaded, than the debugger shouldn't know anything about it
446 // so there shouldn't be any harm in not notifying it of the update. For completeness,
447 // we may want to consider changing this to notify the debugger here as well.
448 MethodTable * pParentType = LookupTypeDef(parentTypeDef).AsMethodTable();
449 if (pParentType == NULL)
451 LOG((LF_ENC, LL_INFO100, "EnCModule::AF class %p not loaded, our work is done\n", parentTypeDef));
455 // Create a new EnCFieldDesc for the field and add it to the class
456 LOG((LF_ENC, LL_INFO100000, "EACM::AM: Adding field %p\n", token));
457 EnCFieldDesc *pField;
458 hr = EEClass::AddField(pParentType, token, &pField);
462 LOG((LF_ENC, LL_INFO100000, "**Error** EACM::AF: Failed to add field %p to EE with hr 0x%x\n", token));
466 // Tell the debugger about the new field
467 hr = g_pDebugInterface->AddField(pField, m_applyChangesCount);
470 LOG((LF_ENC, LL_INFO100000, "**Error** EACM::AF: Failed to add field %p to debugger with hr 0x%x\n", token));
474 if (g_BreakOnEnCResolveField == -1)
476 g_BreakOnEnCResolveField = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_EnCResolveField);
483 //---------------------------------------------------------------------------------------
485 // JitUpdatedFunction - Jit the new version of a function for EnC.
488 // pMD - the MethodDesc for the method we want to JIT
489 // pOrigContext - context of thread pointing into original version of the function
492 // Return the address of the newly jitted code or NULL on failure.
494 PCODE EditAndContinueModule::JitUpdatedFunction( MethodDesc *pMD,
495 CONTEXT *pOrigContext)
505 LOG((LF_ENC, LL_INFO100, "EnCModule::JitUpdatedFunction for %s\n",
506 pMD->m_pszDebugMethodName));
508 PCODE jittedCode = NULL;
513 BOOL shouldBreak = CLRConfig::GetConfigValue(
514 CLRConfig::INTERNAL_EncJitUpdatedFunction);
515 if (shouldBreak > 0) {
516 _ASSERTE(!"EncJitUpdatedFunction");
520 // Setup a frame so that has context for the exception
521 // so that gc can crawl the stack and do the right thing.
522 _ASSERTE(pOrigContext);
523 Thread *pCurThread = GetThread();
524 _ASSERTE(pCurThread);
525 FrameWithCookie<ResumableFrame> resFrame(pOrigContext);
526 resFrame.Push(pCurThread);
528 CONTEXT *pCtxTemp = NULL;
529 // We need to zero out the filter context so a multi-threaded GC doesn't result
530 // in somebody else tracing this thread & concluding that we're in JITted code.
531 // We need to remove the filter context so that if we're in preemptive GC
532 // mode, we'll either have the filter context, or the ResumableFrame,
533 // but not both, set.
534 // Since we're in cooperative mode here, we can swap the two non-atomically here.
535 pCtxTemp = pCurThread->GetFilterContext();
536 _ASSERTE(pCtxTemp != NULL); // currently called from within a filter context, protects us during GC-toggle.
537 pCurThread->SetFilterContext(NULL);
539 // get the code address (may jit the fcn if not already jitted)
541 if (!pMD->IsPointingToNativeCode())
544 pMD->DoPrestub(NULL);
545 LOG((LF_ENC, LL_INFO100, "EnCModule::ResumeInUpdatedFunction JIT successful\n"));
549 LOG((LF_ENC, LL_INFO100, "EnCModule::ResumeInUpdatedFunction function already JITed\n"));
551 jittedCode = pMD->GetNativeCode();
555 // This is debug-only code to print out the error string, but SString can throw.
556 // This function is no-throw, and we can't put an EX_TRY inside an EX_CATCH block, so
557 // we just have the violation.
558 CONTRACT_VIOLATION(ThrowsViolation);
560 StackSString exceptionMessage;
561 SString errorMessage;
562 GetExceptionMessage(GET_THROWABLE(), exceptionMessage);
563 errorMessage.AppendASCII("**Error: Probable rude edit.**\n\n"
564 "EnCModule::JITUpdatedFunction JIT failed with the following exception:\n\n");
565 errorMessage.Append(exceptionMessage);
566 StackScratchBuffer buffer;
567 DbgAssertDialog(__FILE__, __LINE__, errorMessage.GetANSI(buffer));
568 LOG((LF_ENC, LL_INFO100, errorMessage.GetANSI(buffer)));
571 } EX_END_CATCH(SwallowAllExceptions)
573 resFrame.Pop(pCurThread);
575 // Restore the filter context here (see comment above)
576 pCurThread->SetFilterContext(pCtxTemp);
582 //-----------------------------------------------------------------------------
583 // Called by EnC to resume the code in a new version of the function.
585 // 1) jit the new function
586 // 2) set the IP to newILOffset within that new function
587 // 3) adjust local variables (particularly enregistered vars) to the new func.
588 // It will not return.
591 // pMD - method desc for method being updated. This is not enc-version aware.
592 // oldDebuggerFuncHandle - Debugger DJI to uniquely identify old function.
593 // This is enc-version aware.
594 // newILOffset - the IL offset to resume execution at within the new function.
595 // pOrigContext - context of thread pointing into original version of the function.
597 // This function must be called on the thread that's executing the old function.
598 // This function does not return. Instead, it will remap this thread directly
599 // to be executing the new function.
600 //-----------------------------------------------------------------------------
601 HRESULT EditAndContinueModule::ResumeInUpdatedFunction(
603 void *oldDebuggerFuncHandle,
605 CONTEXT *pOrigContext)
607 LOG((LF_ENC, LL_INFO100, "EnCModule::ResumeInUpdatedFunction for %s at IL offset 0x%x, ",
608 pMD->m_pszDebugMethodName, newILOffset));
611 BOOL shouldBreak = CLRConfig::GetConfigValue(
612 CLRConfig::INTERNAL_EncResumeInUpdatedFunction);
613 if (shouldBreak > 0) {
614 _ASSERTE(!"EncResumeInUpdatedFunction");
620 // JIT-compile the updated version of the method
621 PCODE jittedCode = JitUpdatedFunction(pMD, pOrigContext);
622 if ( jittedCode == NULL )
623 return CORDBG_E_ENC_JIT_CANT_UPDATE;
627 // This will create a new frame and copy old vars to it
628 // need pointer to old & new code, old & new info
630 EECodeInfo oldCodeInfo(GetIP(pOrigContext));
631 _ASSERTE(oldCodeInfo.GetMethodDesc() == pMD);
633 // Get the new native offset & IP from the new IL offset
634 LOG((LF_ENC, LL_INFO10000, "EACM::RIUF: About to map IL forwards!\n"));
635 SIZE_T newNativeOffset = 0;
636 g_pDebugInterface->MapILInfoToCurrentNative(pMD,
641 EECodeInfo newCodeInfo(jittedCode + newNativeOffset);
642 _ASSERTE(newCodeInfo.GetMethodDesc() == pMD);
644 _ASSERTE(newCodeInfo.GetRelOffset() == newNativeOffset);
646 _ASSERTE(oldCodeInfo.GetCodeManager() == newCodeInfo.GetCodeManager());
648 DWORD oldFrameSize = oldCodeInfo.GetFixedStackSize();
649 DWORD newFrameSize = newCodeInfo.GetFixedStackSize();
651 // FixContextAndResume() will replace the old stack frame of the function with the new
652 // one and will initialize that new frame to null. Anything on the stack where that new
653 // frame sits will be wiped out. This could include anything on the stack right up to or beyond our
654 // current stack from in ResumeInUpdatedFunction. In order to prevent our current frame from being
655 // trashed we determine the maximum amount that the stack could grow by and allocate this as a buffer using
656 // alloca. Then we call FixContextAndResume which can safely rely on the stack because none of it's frames
657 // state or anything lower can be reached by the new frame.
659 if( newFrameSize > oldFrameSize)
661 DWORD frameIncrement = newFrameSize - oldFrameSize;
662 (void)alloca(frameIncrement);
665 // Ask the EECodeManager to actually fill in the context and stack for the new frame so that
666 // values of locals etc. are preserved.
667 LOG((LF_ENC, LL_INFO100, "EnCModule::ResumeInUpdatedFunction calling FixContextAndResume oldNativeOffset: 0x%x, newNativeOffset: 0x%x,"
668 "oldFrameSize: 0x%x, newFrameSize: 0x%x\n",
669 oldCodeInfo.GetRelOffset(), newCodeInfo.GetRelOffset(), oldFrameSize, newFrameSize));
671 FixContextAndResume(pMD,
672 oldDebuggerFuncHandle,
677 // At this point we shouldn't have failed, so this is genuinely erroneous.
678 LOG((LF_ENC, LL_ERROR, "**Error** EnCModule::ResumeInUpdatedFunction returned from ResumeAtJit"));
679 _ASSERTE(!"Should not return from FixContextAndResume()");
683 // If we fail for any reason we have already potentially trashed with new locals and we have also unwound any
684 // Win32 handlers on the stack so cannot ever return from this function.
685 EEPOLICY_HANDLE_FATAL_ERROR(CORDBG_E_ENC_INTERNAL_ERROR);
689 //---------------------------------------------------------------------------------------
691 // FixContextAndResume - Modify the thread context for EnC remap and resume execution
694 // pMD - MethodDesc for the method being remapped
695 // oldDebuggerFuncHandle - Debugger DJI to uniquely identify old function.
696 // pContext - the thread's original CONTEXT when the remap opportunity was hit
697 // pOldCodeInfo - collection of various information about the current frame state
698 // pNewCodeInfo - information about how we want the frame state to be after the remap
704 // WARNING: This method cannot access any stack-data below its frame on the stack
705 // (i.e. anything allocated in a caller frame), so all stack-based arguments must
706 // EXPLICITLY be copied by value and this method cannot be inlined. We may need to expand
707 // the stack frame to accomodate the new method, and so extra buffer space must have
708 // been allocated on the stack. Note that passing a struct by value (via C++) is not
709 // enough to ensure its data is really copied (on x64, large structs may internally be
710 // passed by reference). Thus we explicitly make copies of structs passed in, at the
714 NOINLINE void EditAndContinueModule::FixContextAndResume(
716 void *oldDebuggerFuncHandle,
718 EECodeInfo *pOldCodeInfo,
719 EECodeInfo *pNewCodeInfo)
721 STATIC_CONTRACT_MODE_COOPERATIVE;
722 STATIC_CONTRACT_GC_TRIGGERS; // Sends IPC event
723 STATIC_CONTRACT_THROWS;
725 // Create local copies of all structs passed as arguments to prevent them from being overwritten
727 memcpy(&context, pContext, sizeof(CONTEXT));
730 #if defined(_TARGET_AMD64_)
731 // Since we made a copy of the incoming CONTEXT in context, clear any new flags we
732 // don't understand (like XSAVE), since we'll eventually be passing a CONTEXT based
733 // on this copy to RtlRestoreContext, and this copy doesn't have the extra info
734 // required by the XSAVE or other flags.
736 // FUTURE: No reason to ifdef this for amd64-only, except to make this late fix as
737 // surgical as possible. Would be nice to enable this on x86 early in the next cycle.
738 pContext->ContextFlags &= CONTEXT_ALL;
739 #endif // defined(_TARGET_AMD64_)
741 EECodeInfo oldCodeInfo;
742 memcpy(&oldCodeInfo, pOldCodeInfo, sizeof(EECodeInfo));
743 pOldCodeInfo = &oldCodeInfo;
745 EECodeInfo newCodeInfo;
746 memcpy(&newCodeInfo, pNewCodeInfo, sizeof(EECodeInfo));
747 pNewCodeInfo = &newCodeInfo;
749 const ICorDebugInfo::NativeVarInfo *pOldVarInfo = NULL;
750 const ICorDebugInfo::NativeVarInfo *pNewVarInfo = NULL;
751 SIZE_T oldVarInfoCount = 0;
752 SIZE_T newVarInfoCount = 0;
754 // Get the var info which the codemanager will use for updating
755 // enregistered variables correctly, or variables whose lifetimes differ
756 // at the update point
757 g_pDebugInterface->GetVarInfo(pMD, oldDebuggerFuncHandle, &oldVarInfoCount, &pOldVarInfo);
758 g_pDebugInterface->GetVarInfo(pMD, NULL, &newVarInfoCount, &pNewVarInfo);
761 // save the frame pointer as FixContextForEnC might step on it.
762 LPVOID oldSP = dac_cast<PTR_VOID>(GetSP(pContext));
764 // need to pop the SEH records before write over the stack in FixContextForEnC
765 PopSEHRecords(oldSP);
768 // Ask the EECodeManager to actually fill in the context and stack for the new frame so that
769 // values of locals etc. are preserved.
770 HRESULT hr = pNewCodeInfo->GetCodeManager()->FixContextForEnC(
773 pOldVarInfo, oldVarInfoCount,
775 pNewVarInfo, newVarInfoCount);
777 // If FixContextForEnC succeeded, the stack is potentially trashed with any new locals and we have also unwound
778 // any Win32 handlers on the stack so cannot ever return from this function. If FixContextForEnC failed, can't
779 // assume that the stack is still intact so apply the proper policy for a fatal EE error to bring us down
780 // "gracefully" (it's all relative).
783 LOG((LF_ENC, LL_INFO100, "**Error** EnCModule::ResumeInUpdatedFunction for FixContextForEnC failed\n"));
784 EEPOLICY_HANDLE_FATAL_ERROR(hr);
788 // Note that all we're really doing here is setting the IP register. We unfortunately don't
789 // share any code with the implementation of debugger SetIP, despite the similarities.
790 LOG((LF_ENC, LL_INFO100, "EnCModule::ResumeInUpdatedFunction: Resume at EIP=0x%x\n", pNewCodeInfo->GetCodeAddress()));
792 Thread *pCurThread = GetThread();
793 _ASSERTE(pCurThread);
795 pCurThread->SetFilterContext(pContext);
796 SetIP(pContext, pNewCodeInfo->GetCodeAddress());
798 // Notify the debugger that we're about to resume execution in the new version of the method
799 HRESULT hrIgnore = g_pDebugInterface->RemapComplete(pMD, pNewCodeInfo->GetCodeAddress(), pNewCodeInfo->GetRelOffset());
801 // Now jump into the new version of the method. Note that we can't just setup the filter context
802 // and return because we are potentially writing new vars onto the stack.
803 pCurThread->SetFilterContext( NULL );
805 #if defined(_TARGET_X86_)
806 ResumeAtJit(pContext, oldSP);
808 RtlRestoreContext(pContext, NULL);
811 // At this point we shouldn't have failed, so this is genuinely erroneous.
812 LOG((LF_ENC, LL_ERROR, "**Error** EnCModule::ResumeInUpdatedFunction returned from ResumeAtJit"));
813 _ASSERTE(!"Should not return from ResumeAtJit()");
815 #endif // #ifndef DACCESS_COMPILE
817 //---------------------------------------------------------------------------------------
818 // ResolveField - get a pointer to the value of a field that was added by EnC
821 // thisPointer - For instance fields, a pointer to the object instance of interest.
822 // For static fields this is unused and should be NULL.
823 // pFD - FieldDesc describing the field we're interested in
824 // fAllocateNew - If storage doesn't yet exist for this field and fAllocateNew is true
825 // then we will attempt to allocate the storage (throwing an exception
826 // if it fails). Otherwise, if fAllocateNew is false, then we will just
827 // return NULL when the storage is not yet available.
830 // If storage doesn't yet exist for this field we return NULL, otherwise, we return a pointer
831 // to the contents of the field on success.
832 //---------------------------------------------------------------------------------------
833 PTR_CBYTE EditAndContinueModule::ResolveField(OBJECTREF thisPointer,
845 if (g_BreakOnEnCResolveField == 1)
847 _ASSERTE( !"EditAndContinueModule::ResolveField");
851 // If it's static, we stash in the EnCFieldDesc
854 _ASSERTE( thisPointer == NULL );
855 EnCAddedStaticField *pAddedStatic = pFD->GetStaticFieldData();
861 _ASSERTE( pAddedStatic->m_pFieldDesc == pFD );
862 return PTR_CBYTE(pAddedStatic->GetFieldData());
865 // not static so get it out of the syncblock
866 SyncBlock * pBlock = NULL;
868 // Get the SyncBlock, failing if not available
869 pBlock = thisPointer->PassiveGetSyncBlock();
875 EnCSyncBlockInfo * pEnCInfo = NULL;
877 // Attempt to get the EnC information from the sync block
878 pEnCInfo = pBlock->GetEnCInfo();
882 // No EnC info on this object yet, fail since we don't want to allocate it
886 // Lookup the actual field value from the EnCSyncBlockInfo
887 return pEnCInfo->ResolveField(thisPointer, pFD);
888 } // EditAndContinueModule::ResolveField
890 #ifndef DACCESS_COMPILE
891 //---------------------------------------------------------------------------------------
892 // ResolveOrAllocateField - get a pointer to the value of a field that was added by EnC,
893 // allocating storage for it if necessary
896 // thisPointer - For instance fields, a pointer to the object instance of interest.
897 // For static fields this is unused and should be NULL.
898 // pFD - FieldDesc describing the field we're interested in
900 // Returns a pointer to the contents of the field on success. This should only fail due
901 // to out-of-memory and will therefore throw an OOM exception.
902 //---------------------------------------------------------------------------------------
903 PTR_CBYTE EditAndContinueModule::ResolveOrAllocateField(OBJECTREF thisPointer,
913 // first try getting a pre-existing field
914 PTR_CBYTE fieldAddr = ResolveField(thisPointer, pFD);
915 if (fieldAddr != NULL)
920 // we didn't find the field already allocated
923 _ASSERTE(thisPointer == NULL);
924 EnCAddedStaticField * pAddedStatic = pFD->GetOrAllocateStaticFieldData();
925 _ASSERTE(pAddedStatic->m_pFieldDesc == pFD);
926 return PTR_CBYTE(pAddedStatic->GetFieldData());
929 // not static so get it out of the syncblock
930 SyncBlock* pBlock = NULL;
932 // Get the SyncBlock, creating it if necessary
933 pBlock = thisPointer->GetSyncBlock();
935 EnCSyncBlockInfo * pEnCInfo = NULL;
937 // Attempt to get the EnC information from the sync block
938 pEnCInfo = pBlock->GetEnCInfo();
942 // Attach new EnC field info to this object.
943 pEnCInfo = new EnCSyncBlockInfo;
948 pBlock->SetEnCInfo(pEnCInfo);
951 // Lookup the actual field value from the EnCSyncBlockInfo
952 return pEnCInfo->ResolveOrAllocateField(thisPointer, pFD);
953 } // EditAndContinueModule::ResolveOrAllocateField
955 #endif // !DACCESS_COMPILE
957 //-----------------------------------------------------------------------------
958 // Get or optionally create an EnCEEClassData object for the specified
959 // EEClass in this module.
962 // pClass - the EEClass of interest
963 // getOnly - if false (the default), we'll create a new entry of none exists yet
965 // Note: If called in a DAC build, GetOnly must be TRUE
967 PTR_EnCEEClassData EditAndContinueModule::GetEnCEEClassData(MethodTable * pMT, BOOL getOnly /*=FALSE*/ )
976 #ifdef DACCESS_COMPILE
977 _ASSERTE(getOnly == TRUE);
978 #endif // DACCESS_COMPILE
980 DPTR(PTR_EnCEEClassData) ppData = m_ClassList.Table();
981 DPTR(PTR_EnCEEClassData) ppLast = ppData + m_ClassList.Count();
983 // Look for an existing entry for the specified class
984 while (ppData < ppLast)
986 PREFIX_ASSUME(ppLast != NULL);
987 if ((*ppData)->GetMethodTable() == pMT)
992 // No match found. Return now if we don't want to create a new entry
998 #ifndef DACCESS_COMPILE
999 // Create a new entry and add it to the end our our table
1000 EnCEEClassData *pNewData = (EnCEEClassData*)(void*)pMT->GetLoaderAllocator()->GetLowFrequencyHeap()->AllocMem_NoThrow(S_SIZE_T(sizeof(EnCEEClassData)));
1001 pNewData->Init(pMT);
1002 ppData = m_ClassList.Append();
1013 // Computes the address of this field within the object "o"
1014 void *EnCFieldDesc::GetAddress( void *o)
1016 #ifndef DACCESS_COMPILE
1022 // can't throw through FieldDesc::GetInstanceField if FORBIDGC_LOADER_USE_ENABLED
1023 _ASSERTE(! FORBIDGC_LOADER_USE_ENABLED());
1025 EditAndContinueModule *pModule = (EditAndContinueModule*)GetModule();
1026 _ASSERTE(pModule->IsEditAndContinueEnabled());
1028 // EnC added fields aren't just at some static offset in the object like normal fields
1029 // are. Get the EditAndContinueModule to compute the address for us.
1030 return (void *)pModule->ResolveOrAllocateField(ObjectToOBJECTREF((Object *)o), this);
1037 #ifndef DACCESS_COMPILE
1039 // Do simple field initialization
1040 // We do this when the process is suspended for debugging (in a GC_NOTRIGGER).
1041 // Full initialization will be done in Fixup when the process is running.
1042 void EnCFieldDesc::Init(mdFieldDef token, BOOL fIsStatic)
1052 // Clear out the FieldDesc incase someone attempts to use any of the fields
1053 memset( this, 0, sizeof(EnCFieldDesc) );
1055 // Initialize our members
1056 m_pStaticFieldData = NULL;
1057 m_bNeedsFixup = TRUE;
1059 // Initialize the bare minimum of FieldDesc necessary for now
1061 FieldDesc::m_isStatic = TRUE;
1063 SetMemberDef(token);
1068 // Allocate a new EnCAddedField instance and hook it up to hold the value for an instance
1069 // field which was added by EnC to the specified object. This effectively adds a reference from
1070 // the object to the new field value so that the field's lifetime is managed properly.
1073 // pFD - description of the field being added
1074 // thisPointer - object instance to attach the new field to
1076 EnCAddedField *EnCAddedField::Allocate(OBJECTREF thisPointer, EnCFieldDesc *pFD)
1086 LOG((LF_ENC, LL_INFO1000, "\tEnCAF:Allocate for this %p, FD %p\n", thisPointer, pFD->GetMemberDef()));
1088 // Create a new EnCAddedField instance
1089 EnCAddedField *pEntry = new EnCAddedField;
1090 pEntry->m_pFieldDesc = pFD;
1092 AppDomain *pDomain = (AppDomain*) pFD->GetApproxEnclosingMethodTable()->GetDomain();
1094 // We need to associate the contents of the new field with the object it is attached to
1095 // in a way that mimics the lifetime behavior of a normal field reference. Specifically,
1096 // when the object is collected, the field should also be collected (assuming there are no
1097 // other references), but references to the field shouldn't keep the object alive.
1098 // To achieve this, we have introduced the concept of a "dependent handle" which provides
1099 // the appropriate semantics. The dependent handle has a weak reference to a "primary object"
1100 // (the object getting a new field in this case), and a strong reference to a secondary object.
1101 // When the primary object is collected, the reference to the secondary object is released.
1102 // See the definition of code:HNDTYPE_DEPENDENT and code:Ref_ScanDependentHandles for more details.
1104 // We create a helper object and store it as the secondary object in the dependant handle
1105 // so that its liveliness can be maintained along with the primary object.
1106 // The helper then contains an object reference to the real field value that we are adding.
1107 // The reason for doing this is that we cannot hand out the handle address for
1108 // the OBJECTREF address so we need to hand out something else that is hooked up to the handle.
1110 GCPROTECT_BEGIN(thisPointer);
1111 MethodTable *pHelperMT = MscorlibBinder::GetClass(CLASS__ENC_HELPER);
1112 pEntry->m_FieldData = pDomain->CreateDependentHandle(thisPointer, AllocateObject(pHelperMT));
1115 LOG((LF_ENC, LL_INFO1000, "\tEnCAF:Allocate created dependent handle %p\n",pEntry->m_FieldData));
1117 // The EnC helper object stores a reference to the actual field value. For fields which are
1118 // reference types, this is simply a normal object reference so we don't need to do anything
1121 if (pFD->GetFieldType() != ELEMENT_TYPE_CLASS)
1123 // The field is a value type so we need to create storage on the heap to hold a boxed
1124 // copy of the value and have the helper's objectref point there.
1126 OBJECTREF obj = NULL;
1127 if (pFD->IsByValue())
1129 // Create a boxed version of the value class. This allows the standard GC algorithm
1130 // to take care of internal pointers into the value class.
1131 obj = AllocateObject(pFD->GetFieldTypeHandleThrowing().GetMethodTable());
1135 // In the case of primitive types, we use a reference to a 1-element array on the heap.
1136 // I'm not sure why we bother treating primitives specially, it seems like we should be able
1137 // to just box any value type including primitives.
1138 obj = AllocatePrimitiveArray(ELEMENT_TYPE_I1, GetSizeForCorElementType(pFD->GetFieldType()));
1140 GCPROTECT_BEGIN (obj);
1142 // Get a FieldDesc for the object reference field in the EnC helper object (warning: triggers)
1143 FieldDesc *pHelperField = MscorlibBinder::GetField(FIELD__ENC_HELPER__OBJECT_REFERENCE);
1145 // store the empty boxed object into the helper object
1146 IGCHandleManager *mgr = GCHandleUtilities::GetGCHandleManager();
1147 OBJECTREF pHelperObj = ObjectToOBJECTREF(mgr->GetDependentHandleSecondary(pEntry->m_FieldData));
1148 OBJECTREF *pHelperRef = (OBJECTREF *)pHelperField->GetAddress( pHelperObj->GetAddress() );
1149 SetObjectReference( pHelperRef, obj);
1156 #endif // !DACCESS_COMPILE
1158 //---------------------------------------------------------------------------------------
1159 // EnCSyncBlockInfo::GetEnCFieldAddrFromHelperFieldDesc
1160 // Gets the address of an EnC field accounting for its type: valuetype, class or primitive
1162 // input: pHelperFieldDesc - FieldDesc for the enc helper object
1163 // pHelper - EnC helper (points to list of added fields)
1164 // pFD - fieldDesc describing the field of interest
1165 // Return value: the address of the EnC added field
1166 //---------------------------------------------------------------------------------------
1167 PTR_CBYTE EnCSyncBlockInfo::GetEnCFieldAddrFromHelperFieldDesc(FieldDesc * pHelperFieldDesc,
1171 WRAPPER_NO_CONTRACT;
1174 _ASSERTE(pHelperFieldDesc != NULL);
1175 _ASSERTE(pHelper != NULL);
1177 // Get the address of the reference inside the helper object which points to
1178 // the field contents
1179 PTR_OBJECTREF pOR = dac_cast<PTR_OBJECTREF>(pHelperFieldDesc->GetAddress(pHelper->GetAddress()));
1180 _ASSERTE(pOR != NULL);
1182 PTR_CBYTE retAddr = NULL;
1184 // Compute the address to the actual field contents based on the field type
1185 // See the description above Allocate for details
1186 if (pFD->IsByValue())
1188 // field value is a value type, we store it boxed so get the pointer to the first field
1189 retAddr = dac_cast<PTR_CBYTE>((*pOR)->UnBox());
1191 else if (pFD->GetFieldType() == ELEMENT_TYPE_CLASS)
1193 // field value is a reference type, we store the objref directly
1194 retAddr = dac_cast<PTR_CBYTE>(pOR);
1198 // field value is a primitive, we store it inside a 1-element array
1199 OBJECTREF objRef = *pOR;
1200 I1ARRAYREF primitiveArray = dac_cast<I1ARRAYREF>(objRef);
1201 retAddr = dac_cast<PTR_CBYTE>(primitiveArray->GetDirectPointerToNonObjectElements());
1204 LOG((LF_ENC, LL_INFO1000, "\tEnCSBI:RF address of %s type member is %p\n",
1205 (pFD->IsByValue() ? "ByValue" : pFD->GetFieldType() == ELEMENT_TYPE_CLASS ? "Class" : "Other"), retAddr));
1208 } // EnCSyncBlockInfo::GetEnCFieldAddrFromHelperFieldDesc
1210 //---------------------------------------------------------------------------------------
1211 // EnCSyncBlockInfo::ResolveField
1212 // Get the address of the data referenced by an instance field that was added with EnC
1214 // thisPointer - the object instance whose field to access
1215 // pFD - fieldDesc describing the field of interest
1216 // Return value: Returns a pointer to the data referenced by an EnC added instance field
1217 //---------------------------------------------------------------------------------------
1218 PTR_CBYTE EnCSyncBlockInfo::ResolveField(OBJECTREF thisPointer, EnCFieldDesc *pFD)
1228 // We should only be passed FieldDescs for instance fields
1229 _ASSERTE(!pFD->IsStatic());
1231 PTR_EnCAddedField pEntry = NULL;
1233 LOG((LF_ENC, LL_INFO1000, "EnCSBI:RF for this %p, FD %p\n", thisPointer, pFD->GetMemberDef()));
1235 // This list is not synchronized--it hasn't proved a problem, but we could conceivably see race conditions
1237 // Look for an entry for the requested field in our linked list
1239 while (pEntry && pEntry->m_pFieldDesc != pFD)
1241 pEntry = pEntry->m_pNext;
1246 // No existing entry - we have to return NULL
1250 // we found a matching entry in the list of EnCAddedFields
1251 // Get the EnC helper object (see the detailed description in Allocate above)
1252 #ifdef DACCESS_COMPILE
1253 OBJECTREF pHelper = GetDependentHandleSecondary(pEntry->m_FieldData);
1254 #else // DACCESS_COMPILE
1255 IGCHandleManager *mgr = GCHandleUtilities::GetGCHandleManager();
1256 OBJECTREF pHelper = ObjectToOBJECTREF(mgr->GetDependentHandleSecondary(pEntry->m_FieldData));
1257 #endif // DACCESS_COMPILE
1258 _ASSERTE(pHelper != NULL);
1260 FieldDesc *pHelperFieldDesc = NULL;
1262 // We _HAVE_ to call GetExistingField b/c (a) we can't throw exceptions, and
1263 // (b) we _DON'T_ want to run class init code, either.
1264 pHelperFieldDesc = MscorlibBinder::GetExistingField(FIELD__ENC_HELPER__OBJECT_REFERENCE);
1265 if (pHelperFieldDesc == NULL)
1271 return GetEnCFieldAddrFromHelperFieldDesc(pHelperFieldDesc, pHelper, pFD);
1273 } // EnCSyncBlockInfo::ResolveField
1275 #ifndef DACCESS_COMPILE
1276 //---------------------------------------------------------------------------------------
1277 // EnCSyncBlockInfo::ResolveOrAllocateField
1278 // get the address of an EnC added field, allocating it if it doesn't yet exist
1280 // thisPointer - the object instance whose field to access
1281 // pFD - fieldDesc describing the field of interest
1282 // Return value: Returns a pointer to the data referenced by an instance field that was added with EnC
1283 //---------------------------------------------------------------------------------------
1284 PTR_CBYTE EnCSyncBlockInfo::ResolveOrAllocateField(OBJECTREF thisPointer, EnCFieldDesc *pFD)
1293 // We should only be passed FieldDescs for instance fields
1294 _ASSERTE( !pFD->IsStatic() );
1296 // first try to get the address of a pre-existing field (storage has already been allocated)
1297 PTR_CBYTE retAddr = ResolveField(thisPointer, pFD);
1299 if (retAddr != NULL)
1304 // if the field doesn't yet have available storage, we'll have to allocate it.
1305 PTR_EnCAddedField pEntry = NULL;
1307 LOG((LF_ENC, LL_INFO1000, "EnCSBI:RF for this %p, FD %p\n", thisPointer, pFD->GetMemberDef()));
1309 // This list is not synchronized--it hasn't proved a problem, but we could conceivably see race conditions
1311 // Because we may have additions to the head of m_pList at any time, we have to keep searching this
1312 // until we either find a match or succeed in allocating a new entry and adding it to the list
1315 // Look for an entry for the requested field in our linked list (maybe it was just added)
1317 while (pEntry && pEntry->m_pFieldDesc != pFD)
1319 pEntry = pEntry->m_pNext;
1328 // Allocate an entry and tie it to the object instance
1329 pEntry = EnCAddedField::Allocate(thisPointer, pFD);
1331 // put at front of list so the list is in order of most recently added
1332 pEntry->m_pNext = m_pList;
1333 if (FastInterlockCompareExchangePointer(&m_pList, pEntry, pEntry->m_pNext) == pEntry->m_pNext)
1336 // There was a race and another thread modified the list here, so we need to try again
1337 // We should do this so rarely, and EnC perf is of relatively little
1338 // consequence, we should just be taking a lock here to simplify this code.
1339 // @todo - We leak a GC handle here. Allocate() above alloced a GC handle in m_FieldData.
1340 // There's no dtor for pEntry to free it.
1344 // we found a matching entry in the list of EnCAddedFields
1345 // Get the EnC helper object (see the detailed description in Allocate above)
1346 IGCHandleManager *mgr = GCHandleUtilities::GetGCHandleManager();
1347 OBJECTREF pHelper = ObjectToOBJECTREF(mgr->GetDependentHandleSecondary(pEntry->m_FieldData));
1348 _ASSERTE(pHelper != NULL);
1350 FieldDesc * pHelperField = NULL;
1351 GCPROTECT_BEGIN (pHelper);
1352 pHelperField = MscorlibBinder::GetField(FIELD__ENC_HELPER__OBJECT_REFERENCE);
1355 return GetEnCFieldAddrFromHelperFieldDesc(pHelperField, pHelper, pFD);
1356 } // EnCSyncBlockInfo::ResolveOrAllocateField
1358 // Free all the resources associated with the fields added to this object instance
1359 // This is invoked after the object instance has been collected, and the SyncBlock is
1362 // Note, this is not threadsafe, and so should only be called when we know no-one else
1363 // maybe using this SyncBlockInfo.
1364 void EnCSyncBlockInfo::Cleanup()
1373 // Walk our linked list of all the fields that were added
1374 EnCAddedField *pEntry = m_pList;
1377 // Clean up the handle we created in EnCAddedField::Allocate
1378 DestroyDependentHandle(*(OBJECTHANDLE*)&pEntry->m_FieldData);
1380 // Delete this list entry and move onto the next
1381 EnCAddedField *next = pEntry->m_pNext;
1386 // Finally, delete the sync block info itself
1390 // Allocate space to hold the value for the new static field
1391 EnCAddedStaticField *EnCAddedStaticField::Allocate(EnCFieldDesc *pFD)
1400 AppDomain *pDomain = (AppDomain*) pFD->GetApproxEnclosingMethodTable()->GetDomain();
1402 // Compute the size of the fieldData entry
1404 if (pFD->IsByValue() || pFD->GetFieldType() == ELEMENT_TYPE_CLASS) {
1405 // We store references to reference types or boxed value types
1406 fieldSize = sizeof(OBJECTREF*);
1408 // We store primitives inline
1409 fieldSize = GetSizeForCorElementType(pFD->GetFieldType());
1412 // allocate an instance with space for the field data
1413 EnCAddedStaticField *pEntry = (EnCAddedStaticField *)
1414 (void*)pDomain->GetHighFrequencyHeap()->AllocMem(S_SIZE_T(offsetof(EnCAddedStaticField, m_FieldData)) + S_SIZE_T(fieldSize));
1415 pEntry->m_pFieldDesc = pFD;
1417 // Create a static objectref to point to the field contents, except for primitives
1418 // which will use the memory available in-line at m_FieldData for storage.
1419 // We use static object refs for static fields as these fields won't go away
1420 // unless the module is unloaded, and they can easily be found by GC.
1421 if (pFD->IsByValue())
1423 // create a boxed version of the value class. This allows the standard GC
1424 // algorithm to take care of internal pointers in the value class.
1425 OBJECTREF **pOR = (OBJECTREF**)&pEntry->m_FieldData;
1426 *pOR = pDomain->AllocateStaticFieldObjRefPtrs(1);
1427 OBJECTREF obj = AllocateObject(pFD->GetFieldTypeHandleThrowing().GetMethodTable());
1428 SetObjectReference( *pOR, obj);
1430 else if (pFD->GetFieldType() == ELEMENT_TYPE_CLASS)
1432 // references to reference-types are stored directly in the field data
1433 OBJECTREF **pOR = (OBJECTREF**)&pEntry->m_FieldData;
1434 *pOR = pDomain->AllocateStaticFieldObjRefPtrs(1);
1439 #endif // !DACCESS_COMPILE
1440 // GetFieldData - return the ADDRESS where the field data is located
1441 PTR_CBYTE EnCAddedStaticField::GetFieldData()
1443 LIMITED_METHOD_CONTRACT;
1446 if ( (m_pFieldDesc->IsByValue()) || (m_pFieldDesc->GetFieldType() == ELEMENT_TYPE_CLASS) )
1448 // It's indirect via an ObjRef at m_FieldData. This is a TADDR, so we need to make a PTR_CBYTE from
1450 return *(PTR_CBYTE *)&m_FieldData;
1454 // An elementry type. It's stored directly in m_FieldData. In this case, we need to get the target
1455 // address of the m_FieldData data member and marshal it via the DAC.
1456 return dac_cast<PTR_CBYTE>(PTR_HOST_MEMBER_TADDR(EnCAddedStaticField, this, m_FieldData));
1460 // Gets a pointer to the field's contents (assuming this is a static field)
1461 // We'll return NULL if we don't yet have a pointer to the data.
1463 // Return value: address of the static field data if available or NULL otherwise
1464 EnCAddedStaticField * EnCFieldDesc::GetStaticFieldData()
1474 _ASSERTE(IsStatic());
1476 return m_pStaticFieldData;
1479 #ifndef DACCESS_COMPILE
1480 // Gets a pointer to the field's contents (assuming this is a static field)
1482 // Return value: address of the field data. If we don't yet have a pointer to the data,
1483 // this will allocate space to store it.
1485 EnCAddedStaticField * EnCFieldDesc::GetOrAllocateStaticFieldData()
1494 _ASSERTE(IsStatic());
1496 // If necessary and requested, allocate space for the static field data
1497 if (!m_pStaticFieldData)
1499 m_pStaticFieldData = EnCAddedStaticField::Allocate(this);
1502 return m_pStaticFieldData;
1504 #endif // !DACCESS_COMPILE
1506 #ifndef DACCESS_COMPILE
1507 // Adds the provided new field to the appropriate linked list and updates the appropriate count
1508 void EnCEEClassData::AddField(EnCAddedFieldElement *pAddedField)
1510 LIMITED_METHOD_CONTRACT;
1511 // Determine the appropriate field list and update the field counter
1512 EnCFieldDesc *pFD = &pAddedField->m_fieldDesc;
1513 EnCAddedFieldElement **pList;
1514 if (pFD->IsStatic())
1516 ++m_dwNumAddedStaticFields;
1517 pList = &m_pAddedStaticFields;
1521 ++m_dwNumAddedInstanceFields;
1522 pList = &m_pAddedInstanceFields;
1525 // If the list is empty, just add this field as the only entry
1528 *pList = pAddedField;
1532 // Otherwise, add this field to the end of the field list
1533 EnCAddedFieldElement *pCur = *pList;
1534 while (pCur->m_next != NULL)
1536 pCur = pCur->m_next;
1538 pCur->m_next = pAddedField;
1541 #endif // #ifndef DACCESS_COMPILE
1543 #ifdef DACCESS_COMPILE
1546 EnCEEClassData::EnumMemoryRegions(CLRDataEnumMemoryFlags flags)
1551 if (m_pMT.IsValid())
1553 m_pMT->EnumMemoryRegions(flags);
1556 PTR_EnCAddedFieldElement elt = m_pAddedInstanceFields;
1557 while (elt.IsValid())
1562 elt = m_pAddedStaticFields;
1563 while (elt.IsValid())
1571 EditAndContinueModule::EnumMemoryRegions(CLRDataEnumMemoryFlags flags,
1581 Module::EnumMemoryRegions(flags, false);
1583 m_ClassList.EnumMemoryRegions();
1585 DPTR(PTR_EnCEEClassData) classData = m_ClassList.Table();
1586 DPTR(PTR_EnCEEClassData) classLast = classData + m_ClassList.Count();
1588 while (classData.IsValid() && classData < classLast)
1590 if ((*classData).IsValid())
1592 (*classData)->EnumMemoryRegions(flags);
1599 #endif // #ifdef DACCESS_COMPILE
1602 // Create a field iterator which includes EnC fields in addition to the fields from an
1603 // underlying ApproxFieldDescIterator.
1606 // pMT - MethodTable indicating the type of interest
1607 // iteratorType - one of the ApproxFieldDescIterator::IteratorType values specifying which fields
1609 // fixupEnC - if true, then any partially-initialized EnC FieldDescs will be fixed up to be complete
1610 // initialized FieldDescs as they are returned by Next(). This may load types and do
1611 // other things to trigger a GC.
1613 EncApproxFieldDescIterator::EncApproxFieldDescIterator(MethodTable *pMT, int iteratorType, BOOL fixupEnC) :
1614 m_nonEnCIter( pMT, iteratorType )
1624 m_fixupEnC = fixupEnC;
1626 #ifndef DACCESS_COMPILE
1627 // can't fixup for EnC on the debugger thread
1628 _ASSERTE((g_pDebugInterface->GetRCThreadId() != GetCurrentThreadId()) || fixupEnC == FALSE);
1631 m_pCurrListElem = NULL;
1632 m_encClassData = NULL;
1633 m_encFieldsReturned = 0;
1635 // If this is an EnC module, then grab a pointer to the EnC data
1636 if( pMT->GetModule()->IsEditAndContinueEnabled() )
1638 PTR_EditAndContinueModule encMod = PTR_EditAndContinueModule(pMT->GetModule());
1639 m_encClassData = encMod->GetEnCEEClassData( pMT, TRUE);
1643 // Iterates through all fields, returns NULL when done.
1644 PTR_FieldDesc EncApproxFieldDescIterator::Next()
1649 if (m_fixupEnC) {GC_TRIGGERS;} else {GC_NOTRIGGER;}
1655 // If we still have non-EnC fields to look at, return one of them
1656 if( m_nonEnCIter.CountRemaining() > 0 )
1658 _ASSERTE( m_encFieldsReturned == 0 );
1659 return m_nonEnCIter.Next();
1662 // Get the next EnC field Desc if any
1663 PTR_EnCFieldDesc pFD = NextEnC();
1670 #ifndef DACCESS_COMPILE
1671 // Fixup the fieldDesc if requested and necessary
1672 if ( m_fixupEnC && (pFD->NeedsFixup()) )
1674 // if we get an OOM during fixup, the field will just not get fixed up
1678 pFD->Fixup(pFD->GetMemberDef());
1683 EX_END_CATCH(SwallowAllExceptions)
1686 // Either it's been fixed up so we can use it, or we're the Debugger RC thread, we can't fix it up,
1687 // but it's ok since our logic will check & make sure we don't try and use it. If haven't asked to
1688 // have the field fixed up, should never be trying to get at non-fixed up field in
1689 // this list. Can't simply fixup the field always because loading triggers GC and many
1690 // code paths can't tolerate that.
1691 _ASSERTE( !(pFD->NeedsFixup()) ||
1692 ( g_pDebugInterface->GetRCThreadId() == GetCurrentThreadId() ) );
1695 return dac_cast<PTR_FieldDesc>(pFD);
1698 // Iterate through EnC added fields.
1699 // Returns NULL when done.
1700 PTR_EnCFieldDesc EncApproxFieldDescIterator::NextEnC()
1711 // If this module doesn't have any EnC data then there aren't any EnC fields
1712 if( m_encClassData == NULL )
1717 BOOL doInst = ( GetIteratorType() & (int)ApproxFieldDescIterator::INSTANCE_FIELDS);
1718 BOOL doStatic = ( GetIteratorType() & (int)ApproxFieldDescIterator::STATIC_FIELDS);
1720 int cNumAddedInst = doInst ? m_encClassData->GetAddedInstanceFields() : 0;
1721 int cNumAddedStatics = doStatic ? m_encClassData->GetAddedStaticFields() : 0;
1723 // If we haven't returned anything yet
1724 if ( m_encFieldsReturned == 0 )
1726 _ASSERTE(m_pCurrListElem == NULL);
1728 // We're at the start of the instance list.
1731 m_pCurrListElem = m_encClassData->m_pAddedInstanceFields;
1735 // If we've finished the instance fields (or never wanted to do any)
1736 if ( m_encFieldsReturned == cNumAddedInst)
1738 // We should be at the end of the instance list if doInst is true
1739 _ASSERTE(m_pCurrListElem == NULL);
1741 // We're at the start of the statics list.
1744 m_pCurrListElem = m_encClassData->m_pAddedStaticFields;
1748 // If we don't have any elements to return, then we're done
1749 if (m_pCurrListElem == NULL)
1751 // Verify that we returned the number we expected to
1752 _ASSERTE( m_encFieldsReturned == cNumAddedInst + cNumAddedStatics );
1756 // Advance the list pointer and return the element
1757 m_encFieldsReturned++;
1758 PTR_EnCFieldDesc fd = PTR_EnCFieldDesc(PTR_HOST_MEMBER_TADDR(EnCAddedFieldElement, m_pCurrListElem, m_fieldDesc));
1759 m_pCurrListElem = m_pCurrListElem->m_next;
1763 #endif // EnC_SUPPORTED