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.
18 #include "fieldmarshaler.h"
19 #include "objecthandle.h"
20 #include "siginfo.hpp"
22 #include "dllimportcallback.h"
23 #include "stackwalk.h"
24 #include "dbginterface.h"
27 #ifdef FEATURE_REMOTING
31 #include "clsload.hpp"
33 #include "virtualcallstub.h"
34 #include "mdaassistants.h"
35 #include "dllimport.h"
37 #include "asmconstants.h"
39 #ifdef FEATURE_COMINTEROP
40 #include "comtoclrcall.h"
41 #endif // FEATURE_COMINTEROP
43 #ifdef FEATURE_INTERPRETER
44 #include "interpreter.h"
45 #endif // FEATURE_INTERPRETER
47 #include "argdestination.h"
49 #if CHECK_APP_DOMAIN_LEAKS
50 #define CHECK_APP_DOMAIN GC_CALL_CHECK_APP_DOMAIN
52 #define CHECK_APP_DOMAIN 0
55 //-----------------------------------------------------------------------
57 //-----------------------------------------------------------------------
59 #ifndef DACCESS_COMPILE
61 unsigned dbgStubCtr = 0;
62 unsigned dbgStubTrip = 0xFFFFFFFF;
67 if (!LoggingOn(LF_STUBS, LL_INFO1000000))
71 if (dbgStubCtr > dbgStubTrip) {
72 dbgStubCtr++; // basicly a nop to put a breakpoint on.
75 MethodDesc* method = GetFunction();
78 if (GetVTablePtr() == UMThkCallFrame::GetMethodFrameVPtr())
79 method = ((UMThkCallFrame*) this)->GetUMEntryThunk()->GetMethod();
82 STRESS_LOG3(LF_STUBS, LL_INFO1000000, "STUBS: In Stub with Frame %p assoc Method %pM FrameType = %pV\n", this, method, *((void**) this));
85 const char* frameType;
86 if (GetVTablePtr() == PrestubMethodFrame::GetMethodFrameVPtr())
87 frameType = "PreStub";
89 else if (GetVTablePtr() == UMThkCallFrame::GetMethodFrameVPtr())
90 frameType = "UMThkCallFrame";
92 else if (GetVTablePtr() == PInvokeCalliFrame::GetMethodFrameVPtr())
94 sprintf_s(buff, COUNTOF(buff), "PInvoke CALLI target" FMT_ADDR,
95 DBG_ADDR(((PInvokeCalliFrame*)this)->GetPInvokeCalliTarget()));
98 else if (GetVTablePtr() == StubDispatchFrame::GetMethodFrameVPtr())
99 frameType = "StubDispatch";
100 else if (GetVTablePtr() == ExternalMethodFrame::GetMethodFrameVPtr())
101 frameType = "ExternalMethod";
103 frameType = "Unknown";
106 LOG((LF_STUBS, LL_INFO1000000,
107 "IN %s Stub Method = %s::%s SIG %s ESP of return" FMT_ADDR "\n",
109 method->m_pszDebugClassName,
110 method->m_pszDebugMethodName,
111 method->m_pszDebugMethodSignature,
112 DBG_ADDR(GetReturnAddressPtr())));
114 LOG((LF_STUBS, LL_INFO1000000,
115 "IN %s Stub Method UNKNOWN ESP of return" FMT_ADDR "\n",
117 DBG_ADDR(GetReturnAddressPtr()) ));
119 _ASSERTE(GetThread()->PreemptiveGCDisabled());
122 //-----------------------------------------------------------------------
123 // This function is used to log transitions in either direction
124 // between unmanaged code and CLR/managed code.
125 // This is typically done in a stub that sets up a Frame, which is
126 // passed as an argument to this function.
128 void __stdcall Frame::LogTransition(Frame* frame)
138 BEGIN_ENTRYPOINT_VOIDRET;
141 // On x86, StubLinkerCPU::EmitMethodStubProlog calls Frame::LogTransition
142 // but the caller of EmitMethodStubProlog sets the GSCookie later on.
143 // So the cookie is not initialized by the point we get here.
145 _ASSERTE(*frame->GetGSCookiePtr() == GetProcessGSCookie());
148 if (Frame::ShouldLogTransitions())
151 END_ENTRYPOINT_VOIDRET;
152 } // void Frame::Log()
154 #endif // #ifndef DACCESS_COMPILE
156 //-----------------------------------------------------------------------
158 //-----------------------------------------------------------------------
161 // TODO [DAVBR]: For the full fix for VsWhidbey 450273, all the below
162 // may be uncommented once isLegalManagedCodeCaller works properly
163 // with non-return address inputs, and with non-DEBUG builds
165 //-----------------------------------------------------------------------
166 // returns TRUE if retAddr, is a return address that can call managed code
168 bool isLegalManagedCodeCaller(PCODE retAddr) {
172 // we expect to be called from JITTED code or from special code sites inside
173 // mscorwks like callDescr which we have put a NOP (0x90) so we know that they
174 // are specially blessed.
175 if (!ExecutionManager::IsManagedCode(retAddr) &&
177 #ifdef DACCESS_COMPILE
178 !(PTR_BYTE(retAddr).IsValid()) ||
180 ((*PTR_BYTE(retAddr) != 0x90) &&
181 (*PTR_BYTE(retAddr) != 0xcc))))
183 LOG((LF_GC, LL_INFO10, "Bad caller to managed code: retAddr=0x%08x, *retAddr=0x%x\n",
184 retAddr, *(BYTE*)PTR_BYTE(retAddr)));
189 // it better be a return address of some kind
191 if (isRetAddr(retAddr, &dummy))
194 #ifndef DACCESS_COMPILE
195 #ifdef DEBUGGING_SUPPORTED
196 // The debugger could have dropped an INT3 on the instruction that made the call
197 // Calls can be 2 to 7 bytes long
198 if (CORDebuggerAttached()) {
199 PTR_BYTE ptr = PTR_BYTE(retAddr);
200 for (int i = -2; i >= -7; --i)
205 #endif // DEBUGGING_SUPPORTED
206 #endif // #ifndef DACCESS_COMPILE
208 _ASSERTE(!"Bad return address on stack");
210 #else // _TARGET_X86_
212 #endif // _TARGET_X86_
217 //-----------------------------------------------------------------------
218 // Count of the number of frame types
219 const size_t FRAME_TYPES_COUNT =
220 #define FRAME_TYPE_NAME(frameType) +1
224 #if defined (_DEBUG_IMPL) // _DEBUG and !DAC
226 //-----------------------------------------------------------------------
227 // Implementation of the global table of names. On the DAC side, just the global pointer.
228 // On the runtime side, the array of names.
229 #define FRAME_TYPE_NAME(x) {x::GetMethodFrameVPtr(), #x} ,
230 static FrameTypeName FrameTypeNameTable[] = {
236 PTR_CSTR Frame::GetFrameTypeName(TADDR vtbl)
238 LIMITED_METHOD_CONTRACT;
239 for (size_t i=0; i<FRAME_TYPES_COUNT; ++i)
241 if (vtbl == FrameTypeNameTable[(int)i].vtbl)
243 return FrameTypeNameTable[(int)i].name;
248 } // char* Frame::FrameTypeName()
251 //-----------------------------------------------------------------------
254 void Frame::LogFrame(
255 int LF, // Log facility for this call.
256 int LL) // Log Level for this call.
259 const char *pFrameType;
260 pFrameType = GetFrameTypeName();
262 if (pFrameType == NULL)
264 pFrameType = GetFrameTypeName(GetVTablePtr());
267 if (pFrameType == NULL)
269 _ASSERTE(!"New Frame type needs to be added to FrameTypeName()");
270 // Pointer is up to 17chars + vtbl@ = 22 chars
271 sprintf_s(buf, COUNTOF(buf), "vtbl@%p", GetVTablePtr());
275 LOG((LF, LL, "FRAME: addr:%p, next:%p, type:%s\n",
276 this, m_Next, pFrameType));
277 } // void Frame::LogFrame()
279 void Frame::LogFrameChain(
280 int LF, // Log facility for this call.
281 int LL) // Log Level for this call.
283 if (!LoggingOn(LF, LL))
286 Frame *pFrame = this;
287 while (pFrame != FRAME_TOP)
289 pFrame->LogFrame(LF, LL);
290 pFrame = pFrame->m_Next;
292 } // void Frame::LogFrameChain()
294 //-----------------------------------------------------------------------
295 #endif // _DEBUG_IMPL
296 //-----------------------------------------------------------------------
298 #ifndef DACCESS_COMPILE
300 // This hashtable contains the vtable value of every Frame type.
301 static PtrHashMap* s_pFrameVTables = NULL;
313 // create a table big enough for all the frame types, not in asynchronous mode, and with no lock owner
314 s_pFrameVTables = ::new PtrHashMap;
315 s_pFrameVTables->Init(2 * FRAME_TYPES_COUNT, FALSE, &g_lockTrustMeIAmThreadSafe);
316 #define FRAME_TYPE_NAME(frameType) \
317 s_pFrameVTables->InsertValue(frameType::GetMethodFrameVPtr(), \
318 (LPVOID) frameType::GetMethodFrameVPtr());
321 } // void Frame::Init()
326 LIMITED_METHOD_CONTRACT;
327 delete s_pFrameVTables;
328 s_pFrameVTables = NULL;
331 #endif // DACCESS_COMPILE
333 // Returns true if the Frame's VTablePtr is valid
336 bool Frame::HasValidVTablePtr(Frame * pFrame)
340 if (pFrame == NULL || pFrame == FRAME_TOP)
343 #ifndef DACCESS_COMPILE
344 TADDR vptr = pFrame->GetVTablePtr();
346 // Helper MethodFrame,GCFrame,DebuggerSecurityCodeMarkFrame are the most
347 // common frame types, explicitly check for them.
349 if (vptr == HelperMethodFrame::GetMethodFrameVPtr())
352 if (vptr == GCFrame::GetMethodFrameVPtr())
355 if (vptr == DebuggerSecurityCodeMarkFrame::GetMethodFrameVPtr())
359 // otherwise consult the hashtable
361 if (s_pFrameVTables->LookupValue(vptr, (LPVOID) vptr) == (LPVOID) INVALIDENTRY)
368 // Returns the location of the expected GSCookie,
369 // Return NULL if the frame's vtable pointer is corrupt
371 // Note that Frame::GetGSCookiePtr is a virtual method,
372 // and so it cannot be used without first checking if
373 // the vtable is valid.
376 PTR_GSCookie Frame::SafeGetGSCookiePtr(Frame * pFrame)
380 _ASSERTE(pFrame != FRAME_TOP);
382 if (Frame::HasValidVTablePtr(pFrame))
383 return pFrame->GetGSCookiePtr();
388 //-----------------------------------------------------------------------
389 #ifndef DACCESS_COMPILE
390 //-----------------------------------------------------------------------
391 // Link and Unlink this frame.
392 //-----------------------------------------------------------------------
408 VOID Frame::Push(Thread *pThread)
419 _ASSERTE(*GetGSCookiePtr() == GetProcessGSCookie());
421 m_Next = pThread->GetFrame();
423 // PAGE_SIZE is used to relax the assert for cases where two Frames are
424 // declared in the same source function. We cannot predict the order
425 // in which the C compiler will lay them out in the stack frame.
426 // So PAGE_SIZE is a guess of the maximum stack frame size of any method
427 // with multiple Frames in mscorwks.dll
428 _ASSERTE(((m_Next == FRAME_TOP) ||
429 (PBYTE(m_Next) + (2 * PAGE_SIZE)) > PBYTE(this)) &&
430 "Pushing a frame out of order ?");
432 _ASSERTE(// If AssertOnFailFast is set, the test expects to do stack overrun
433 // corruptions. In that case, the Frame chain may be corrupted,
434 // and the rest of the assert is not valid.
435 // Note that the corrupted Frame chain will be detected
436 // during stack-walking.
437 !g_pConfig->fAssertOnFailFast() ||
438 (m_Next == FRAME_TOP) ||
439 (*m_Next->GetGSCookiePtr() == GetProcessGSCookie()));
441 pThread->SetFrame(this);
458 VOID Frame::Pop(Thread *pThread)
469 _ASSERTE(pThread->GetFrame() == this && "Popping a frame out of order ?");
470 _ASSERTE(*GetGSCookiePtr() == GetProcessGSCookie());
471 _ASSERTE(// If AssertOnFailFast is set, the test expects to do stack overrun
472 // corruptions. In that case, the Frame chain may be corrupted,
473 // and the rest of the assert is not valid.
474 // Note that the corrupted Frame chain will be detected
475 // during stack-walking.
476 !g_pConfig->fAssertOnFailFast() ||
477 (m_Next == FRAME_TOP) ||
478 (*m_Next->GetGSCookiePtr() == GetProcessGSCookie()));
480 pThread->SetFrame(m_Next);
484 #if defined(FEATURE_PAL) && !defined(DACCESS_COMPILE) && !defined(CROSSGEN_COMPILE)
485 void Frame::PopIfChained()
499 // When the frame is destroyed, make sure it is no longer in the
500 // frame chain managed by the Thread.
504 #endif // FEATURE_PAL && !DACCESS_COMPILE && !CROSSGEN_COMPILE
506 //-----------------------------------------------------------------------
507 #endif // #ifndef DACCESS_COMPILE
508 //---------------------------------------------------------------
509 // Get the extra param for shared generic code.
510 //---------------------------------------------------------------
511 PTR_VOID TransitionFrame::GetParamTypeArg()
522 // This gets called while creating stack traces during exception handling.
523 // Using the ArgIterator constructor calls ArgIterator::Init which calls GetInitialOfsAdjust
524 // which calls SizeOfArgStack, which thinks it may load value types.
525 // However all these will have previously been loaded.
527 // I'm not entirely convinced this is the best places to put this: CrawlFrame::GetExactGenericArgsToken
528 // may be another option.
529 ENABLE_FORBID_GC_LOADER_USE_IN_THIS_SCOPE();
531 MethodDesc *pFunction = GetFunction();
532 _ASSERTE (pFunction->RequiresInstArg());
534 MetaSig msig(pFunction);
535 ArgIterator argit (&msig);
537 INT offs = argit.GetParamTypeArgOffset();
539 TADDR taParamTypeArg = *PTR_TADDR(GetTransitionBlock() + offs);
540 return PTR_VOID(taParamTypeArg);
543 TADDR TransitionFrame::GetAddrOfThis()
546 return GetTransitionBlock() + ArgIterator::GetThisOffset();
549 VASigCookie * TransitionFrame::GetVASigCookie()
551 #if defined(_TARGET_X86_)
552 LIMITED_METHOD_CONTRACT;
553 return dac_cast<PTR_VASigCookie>(
554 *dac_cast<PTR_TADDR>(GetTransitionBlock() +
555 sizeof(TransitionBlock)));
558 MetaSig msig(GetFunction());
559 ArgIterator argit(&msig);
560 return PTR_VASigCookie(
561 *dac_cast<PTR_TADDR>(GetTransitionBlock() + argit.GetVASigCookieOffset()));
565 #ifndef DACCESS_COMPILE
566 PrestubMethodFrame::PrestubMethodFrame(TransitionBlock * pTransitionBlock, MethodDesc * pMD)
567 : FramedMethodFrame(pTransitionBlock, pMD)
569 LIMITED_METHOD_CONTRACT;
571 #endif // #ifndef DACCESS_COMPILE
573 BOOL PrestubMethodFrame::TraceFrame(Thread *thread, BOOL fromPatch,
574 TraceDestination *trace, REGDISPLAY *regs)
579 // We want to set a frame patch, unless we're already at the
580 // frame patch, in which case we'll trace stable entrypoint which
581 // should be set by now.
586 trace->InitForStub(GetFunction()->GetStableEntryPoint());
590 trace->InitForStub(GetPreStubEntryPoint());
593 LOG((LF_CORDB, LL_INFO10000,
594 "PrestubMethodFrame::TraceFrame: ip=" FMT_ADDR "\n", DBG_ADDR(trace->GetAddress()) ));
599 #ifndef DACCESS_COMPILE
600 //-----------------------------------------------------------------------
601 // A rather specialized routine for the exclusive use of StubDispatch.
602 //-----------------------------------------------------------------------
603 StubDispatchFrame::StubDispatchFrame(TransitionBlock * pTransitionBlock)
604 : FramedMethodFrame(pTransitionBlock, NULL)
606 LIMITED_METHOD_CONTRACT;
608 m_pRepresentativeMT = NULL;
609 m_representativeSlot = 0;
612 m_pIndirection = NULL;
617 #endif // #ifndef DACCESS_COMPILE
619 MethodDesc* StubDispatchFrame::GetFunction()
627 MethodDesc * pMD = m_pMD;
631 if (m_pRepresentativeMT != NULL)
633 pMD = m_pRepresentativeMT->GetMethodDescForSlot(m_representativeSlot);
634 #ifndef DACCESS_COMPILE
643 static PTR_BYTE FindGCRefMap(PTR_Module pZapModule, TADDR ptr)
645 LIMITED_METHOD_DAC_CONTRACT;
647 PEImageLayout *pNativeImage = pZapModule->GetNativeOrReadyToRunImage();
649 RVA rva = pNativeImage->GetDataRva(ptr);
651 PTR_CORCOMPILE_IMPORT_SECTION pImportSection = pZapModule->GetImportSectionForRVA(rva);
652 if (pImportSection == NULL)
655 COUNT_T index = (rva - pImportSection->Section.VirtualAddress) / pImportSection->EntrySize;
657 PTR_BYTE pGCRefMap = dac_cast<PTR_BYTE>(pNativeImage->GetRvaData(pImportSection->AuxiliaryData));
658 _ASSERTE(pGCRefMap != NULL);
660 // GCRefMap starts with lookup index to limit size of linear scan that follows.
661 PTR_BYTE p = pGCRefMap + dac_cast<PTR_DWORD>(pGCRefMap)[index / GCREFMAP_LOOKUP_STRIDE];
662 COUNT_T remaining = index % GCREFMAP_LOOKUP_STRIDE;
664 while (remaining > 0)
666 while ((*p & 0x80) != 0)
676 PTR_BYTE StubDispatchFrame::GetGCRefMap()
685 PTR_BYTE pGCRefMap = m_pGCRefMap;
687 if (pGCRefMap == NULL)
689 if (m_pIndirection != NULL)
691 if (m_pZapModule == NULL)
693 m_pZapModule = ExecutionManager::FindModuleForGCRefMap(m_pIndirection);
696 if (m_pZapModule != NULL)
698 pGCRefMap = FindGCRefMap(m_pZapModule, m_pIndirection);
701 #ifndef DACCESS_COMPILE
702 if (pGCRefMap != NULL)
704 m_pGCRefMap = pGCRefMap;
708 // Clear the indirection to avoid retrying
709 m_pIndirection = NULL;
718 void StubDispatchFrame::GcScanRoots(promote_func *fn, ScanContext* sc)
727 FramedMethodFrame::GcScanRoots(fn, sc);
729 PTR_BYTE pGCRefMap = GetGCRefMap();
730 if (pGCRefMap != NULL)
732 PromoteCallerStackUsingGCRefMap(fn, sc, pGCRefMap);
736 PromoteCallerStack(fn, sc);
740 BOOL StubDispatchFrame::TraceFrame(Thread *thread, BOOL fromPatch,
741 TraceDestination *trace, REGDISPLAY *regs)
746 // We want to set a frame patch, unless we're already at the
747 // frame patch, in which case we'll trace stable entrypoint which
748 // should be set by now.
753 trace->InitForStub(GetFunction()->GetStableEntryPoint());
757 trace->InitForStub(GetPreStubEntryPoint());
760 LOG((LF_CORDB, LL_INFO10000,
761 "StubDispatchFrame::TraceFrame: ip=" FMT_ADDR "\n", DBG_ADDR(trace->GetAddress()) ));
766 Frame::Interception StubDispatchFrame::GetInterception()
768 LIMITED_METHOD_CONTRACT;
770 return INTERCEPTION_NONE;
773 #ifndef DACCESS_COMPILE
774 ExternalMethodFrame::ExternalMethodFrame(TransitionBlock * pTransitionBlock)
775 : FramedMethodFrame(pTransitionBlock, NULL)
777 LIMITED_METHOD_CONTRACT;
779 m_pIndirection = NULL;
784 #endif // !DACCESS_COMPILE
786 void ExternalMethodFrame::GcScanRoots(promote_func *fn, ScanContext* sc)
795 FramedMethodFrame::GcScanRoots(fn, sc);
796 PromoteCallerStackUsingGCRefMap(fn, sc, GetGCRefMap());
799 PTR_BYTE ExternalMethodFrame::GetGCRefMap()
801 LIMITED_METHOD_DAC_CONTRACT;
803 PTR_BYTE pGCRefMap = m_pGCRefMap;
805 if (pGCRefMap == NULL)
807 if (m_pIndirection != NULL)
809 pGCRefMap = FindGCRefMap(m_pZapModule, m_pIndirection);
810 #ifndef DACCESS_COMPILE
811 m_pGCRefMap = pGCRefMap;
816 _ASSERTE(pGCRefMap != NULL);
820 Frame::Interception ExternalMethodFrame::GetInterception()
822 LIMITED_METHOD_CONTRACT;
824 return INTERCEPTION_NONE;
827 Frame::Interception PrestubMethodFrame::GetInterception()
829 LIMITED_METHOD_DAC_CONTRACT;
832 // The only direct kind of interception done by the prestub
833 // is class initialization.
836 return INTERCEPTION_PRESTUB;
839 #ifdef FEATURE_READYTORUN
841 #ifndef DACCESS_COMPILE
842 DynamicHelperFrame::DynamicHelperFrame(TransitionBlock * pTransitionBlock, int dynamicHelperFrameFlags)
843 : FramedMethodFrame(pTransitionBlock, NULL)
845 LIMITED_METHOD_CONTRACT;
847 m_dynamicHelperFrameFlags = dynamicHelperFrameFlags;
849 #endif // !DACCESS_COMPILE
851 void DynamicHelperFrame::GcScanRoots(promote_func *fn, ScanContext* sc)
860 FramedMethodFrame::GcScanRoots(fn, sc);
862 PTR_PTR_Object pArgumentRegisters = dac_cast<PTR_PTR_Object>(GetTransitionBlock() + TransitionBlock::GetOffsetOfArgumentRegisters());
864 if (m_dynamicHelperFrameFlags & DynamicHelperFrameFlags_ObjectArg)
866 TADDR pArgument = GetTransitionBlock() + TransitionBlock::GetOffsetOfArgumentRegisters();
868 // x86 is special as always
869 pArgument += offsetof(ArgumentRegisters, ECX);
871 (*fn)(dac_cast<PTR_PTR_Object>(pArgument), sc, CHECK_APP_DOMAIN);
874 if (m_dynamicHelperFrameFlags & DynamicHelperFrameFlags_ObjectArg2)
876 TADDR pArgument = GetTransitionBlock() + TransitionBlock::GetOffsetOfArgumentRegisters();
878 // x86 is special as always
879 pArgument += offsetof(ArgumentRegisters, EDX);
881 pArgument += sizeof(TADDR);
883 (*fn)(dac_cast<PTR_PTR_Object>(pArgument), sc, CHECK_APP_DOMAIN);
887 #endif // FEATURE_READYTORUN
890 #ifndef DACCESS_COMPILE
892 #ifdef FEATURE_COMINTEROP
893 //-----------------------------------------------------------------------
894 // A rather specialized routine for the exclusive use of the COM PreStub.
895 //-----------------------------------------------------------------------
897 ComPrestubMethodFrame::Init()
901 // Initializes the frame's VPTR. This assumes C++ puts the vptr
902 // at offset 0 for a class not using MI, but this is no different
903 // than the assumption that COM Classic makes.
904 *((TADDR*)this) = GetMethodFrameVPtr();
905 *GetGSCookiePtr() = GetProcessGSCookie();
907 #endif // FEATURE_COMINTEROP
909 //-----------------------------------------------------------------------
911 //-----------------------------------------------------------------------
914 //--------------------------------------------------------------------
915 // This constructor pushes a new GCFrame on the frame chain.
916 //--------------------------------------------------------------------
917 GCFrame::GCFrame(OBJECTREF *pObjRefs, UINT numObjRefs, BOOL maybeInterior)
928 Init(GetThread(), pObjRefs, numObjRefs, maybeInterior);
931 GCFrame::GCFrame(Thread *pThread, OBJECTREF *pObjRefs, UINT numObjRefs, BOOL maybeInterior)
942 Init(pThread, pObjRefs, numObjRefs, maybeInterior);
945 void GCFrame::Init(Thread *pThread, OBJECTREF *pObjRefs, UINT numObjRefs, BOOL maybeInterior)
956 #ifdef USE_CHECKED_OBJECTREFS
957 if (!maybeInterior) {
959 for(i = 0; i < numObjRefs; i++)
960 Thread::ObjectRefProtected(&pObjRefs[i]);
962 for (i = 0; i < numObjRefs; i++) {
963 pObjRefs[i].Validate();
967 #if 0 // We'll want to restore this goodness check at some time. For now, the fact that we use
968 // this as temporary backstops in our loader exception conversions means we're highly
969 // exposed to infinite stack recursion should the loader be invoked during a stackwalk.
970 // So we'll do without.
972 if (g_pConfig->GetGCStressLevel() != 0 && IsProtectedByGCFrame(pObjRefs)) {
973 _ASSERTE(!"This objectref is already protected by a GCFrame. Protecting it twice will corrupt the GC.");
979 m_pObjRefs = pObjRefs;
980 m_numObjRefs = numObjRefs;
981 m_pCurThread = pThread;
982 m_MaybeInterior = maybeInterior;
984 Frame::Push(m_pCurThread);
989 // GCFrame Object Scanning
991 // This handles scanning/promotion of GC objects that were
992 // protected by the programmer explicitly protecting it in a GC Frame
993 // via the GCPROTECTBEGIN / GCPROTECTEND facility...
996 #endif // !DACCESS_COMPILE
998 void GCFrame::GcScanRoots(promote_func *fn, ScanContext* sc)
1000 WRAPPER_NO_CONTRACT;
1002 PTR_PTR_Object pRefs = dac_cast<PTR_PTR_Object>(m_pObjRefs);
1004 for (UINT i = 0;i < m_numObjRefs; i++) {
1006 LOG((LF_GC, INFO3, "GC Protection Frame Promoting" FMT_ADDR "to",
1007 DBG_ADDR(OBJECTREF_TO_UNCHECKED_OBJECTREF(m_pObjRefs[i])) ));
1008 if (m_MaybeInterior)
1009 PromoteCarefully(fn, pRefs + i, sc, GC_CALL_INTERIOR|CHECK_APP_DOMAIN);
1011 (*fn)(pRefs + i, sc, 0);
1012 LOG((LF_GC, INFO3, FMT_ADDR "\n", DBG_ADDR(OBJECTREF_TO_UNCHECKED_OBJECTREF(m_pObjRefs[i])) ));
1016 #ifdef FEATURE_REMOTING
1017 #include "objectclone.h"
1018 void GCSafeCollectionFrame::GcScanRoots(promote_func *fn, ScanContext* sc)
1020 WRAPPER_NO_CONTRACT;
1022 PTR_GCSafeCollection collection = dac_cast<PTR_GCSafeCollection>(m_pCollection);
1023 collection->ReportGCRefs(fn, sc);
1026 #ifndef DACCESS_COMPILE
1027 GCSafeCollectionFrame::GCSafeCollectionFrame(void *collection)
1029 WRAPPER_NO_CONTRACT;
1031 _ASSERTE(collection != NULL);
1032 m_pCollection = collection;
1037 VOID GCSafeCollectionFrame::Pop()
1039 LIMITED_METHOD_CONTRACT;
1042 #endif // !DACCESS_COMPILE
1043 #endif // FEATURE_REMOTING
1045 #ifndef DACCESS_COMPILE
1046 //--------------------------------------------------------------------
1047 // Pops the GCFrame and cancels the GC protection.
1048 //--------------------------------------------------------------------
1051 WRAPPER_NO_CONTRACT;
1053 Frame::Pop(m_pCurThread);
1055 m_pCurThread->EnableStressHeap();
1056 for(UINT i = 0; i < m_numObjRefs; i++)
1057 Thread::ObjectRefNew(&m_pObjRefs[i]); // Unprotect them
1061 #ifdef FEATURE_INTERPRETER
1062 // Methods of IntepreterFrame.
1063 InterpreterFrame::InterpreterFrame(Interpreter* interp)
1064 : Frame(), m_interp(interp)
1070 MethodDesc* InterpreterFrame::GetFunction()
1072 return m_interp->GetMethodDesc();
1075 void InterpreterFrame::GcScanRoots(promote_func *fn, ScanContext* sc)
1077 return m_interp->GCScanRoots(fn, sc);
1080 #endif // FEATURE_INTERPRETER
1082 #if defined(_DEBUG) && !defined (DACCESS_COMPILE)
1084 struct IsProtectedByGCFrameStruct
1086 OBJECTREF *ppObjectRef;
1090 static StackWalkAction IsProtectedByGCFrameStackWalkFramesCallback(
1095 DEBUG_ONLY_FUNCTION;
1096 WRAPPER_NO_CONTRACT;
1098 IsProtectedByGCFrameStruct *pd = (IsProtectedByGCFrameStruct*)pData;
1099 Frame *pFrame = pCF->GetFrame();
1101 if (pFrame->Protects(pd->ppObjectRef)) {
1105 return SWA_CONTINUE;
1108 BOOL IsProtectedByGCFrame(OBJECTREF *ppObjectRef)
1110 DEBUG_ONLY_FUNCTION;
1111 WRAPPER_NO_CONTRACT;
1113 // Just report TRUE if GCStress is not on. This satisfies the asserts that use this
1114 // code without the cost of actually determining it.
1115 if (!GCStress<cfg_any>::IsEnabled())
1118 if (ppObjectRef == NULL) {
1122 CONTRACT_VIOLATION(ThrowsViolation);
1123 ENABLE_FORBID_GC_LOADER_USE_IN_THIS_SCOPE ();
1124 IsProtectedByGCFrameStruct d = {ppObjectRef, 0};
1125 GetThread()->StackWalkFrames(IsProtectedByGCFrameStackWalkFramesCallback, &d);
1127 _ASSERTE(!"Multiple GCFrames protecting the same pointer. This will cause GC corruption!");
1129 return d.count != 0;
1133 #endif //!DACCESS_COMPILE
1135 void ProtectByRefsFrame::GcScanRoots(promote_func *fn, ScanContext *sc)
1144 ByRefInfo *pByRefInfos = m_brInfo;
1147 if (!CorIsPrimitiveType(pByRefInfos->typ))
1149 TADDR pData = PTR_HOST_MEMBER_TADDR(ByRefInfo, pByRefInfos, data);
1151 if (pByRefInfos->typeHandle.IsValueType())
1153 ReportPointersFromValueType(fn, sc, pByRefInfos->typeHandle.GetMethodTable(), PTR_VOID(pData));
1157 PTR_PTR_Object ppObject = PTR_PTR_Object(pData);
1159 LOG((LF_GC, INFO3, "ProtectByRefs Frame Promoting" FMT_ADDR "to ", DBG_ADDR(*ppObject)));
1161 (*fn)(ppObject, sc, CHECK_APP_DOMAIN);
1163 LOG((LF_GC, INFO3, FMT_ADDR "\n", DBG_ADDR(*ppObject) ));
1166 pByRefInfos = pByRefInfos->pNext;
1170 void ProtectValueClassFrame::GcScanRoots(promote_func *fn, ScanContext *sc)
1179 ValueClassInfo *pVCInfo = m_pVCInfo;
1180 while (pVCInfo != NULL)
1182 _ASSERTE(pVCInfo->pMT->IsValueType());
1183 ReportPointersFromValueType(fn, sc, pVCInfo->pMT, pVCInfo->pData);
1184 pVCInfo = pVCInfo->pNext;
1189 // Promote Caller Stack
1193 void TransitionFrame::PromoteCallerStack(promote_func* fn, ScanContext* sc)
1195 WRAPPER_NO_CONTRACT;
1197 // I believe this is the contract:
1208 MethodDesc *pFunction;
1210 LOG((LF_GC, INFO3, " Promoting method caller Arguments\n" ));
1212 // We're going to have to look at the signature to determine
1213 // which arguments a are pointers....First we need the function
1214 pFunction = GetFunction();
1215 if (pFunction == NULL)
1218 // Now get the signature...
1219 Signature callSignature = pFunction->GetSignature();
1220 if (callSignature.IsEmpty())
1225 //If not "vararg" calling convention, assume "default" calling convention
1226 if (!MetaSig::IsVarArg(pFunction->GetModule(), callSignature))
1228 MetaSig msig(pFunction);
1229 PromoteCallerStackHelper (fn, sc, pFunction, &msig);
1233 VASigCookie *varArgSig = GetVASigCookie();
1235 //Note: no instantiations needed for varargs
1236 MetaSig msig(varArgSig->signature,
1239 PromoteCallerStackHelper (fn, sc, pFunction, &msig);
1243 void TransitionFrame::PromoteCallerStackHelper(promote_func* fn, ScanContext* sc,
1244 MethodDesc *pFunction, MetaSig *pmsig)
1246 WRAPPER_NO_CONTRACT;
1247 // I believe this is the contract:
1258 ArgIterator argit(pmsig);
1260 TADDR pTransitionBlock = GetTransitionBlock();
1262 // promote 'this' for non-static methods
1263 if (argit.HasThis() && pFunction != NULL)
1265 BOOL interior = pFunction->GetMethodTable()->IsValueType() && !pFunction->IsUnboxingStub();
1267 PTR_PTR_VOID pThis = dac_cast<PTR_PTR_VOID>(pTransitionBlock + argit.GetThisOffset());
1269 " 'this' Argument at " FMT_ADDR "promoted from" FMT_ADDR "\n",
1270 DBG_ADDR(pThis), DBG_ADDR(*pThis) ));
1273 PromoteCarefully(fn, PTR_PTR_Object(pThis), sc, GC_CALL_INTERIOR|CHECK_APP_DOMAIN);
1275 (fn)(PTR_PTR_Object(pThis), sc, CHECK_APP_DOMAIN);
1278 if (argit.HasRetBuffArg())
1280 PTR_PTR_VOID pRetBuffArg = dac_cast<PTR_PTR_VOID>(pTransitionBlock + argit.GetRetBuffArgOffset());
1281 LOG((LF_GC, INFO3, " ret buf Argument promoted from" FMT_ADDR "\n", DBG_ADDR(*pRetBuffArg) ));
1282 PromoteCarefully(fn, PTR_PTR_Object(pRetBuffArg), sc, GC_CALL_INTERIOR|CHECK_APP_DOMAIN);
1286 while ((argOffset = argit.GetNextOffset()) != TransitionBlock::InvalidOffset)
1288 ArgDestination argDest(dac_cast<PTR_VOID>(pTransitionBlock), argOffset, argit.GetArgLocDescForStructInRegs());
1289 pmsig->GcScanRoots(&argDest, fn, sc);
1294 UINT TransitionFrame::CbStackPopUsingGCRefMap(PTR_BYTE pGCRefMap)
1296 LIMITED_METHOD_CONTRACT;
1298 GCRefMapDecoder decoder(pGCRefMap);
1299 return decoder.ReadStackPop() * sizeof(TADDR);
1303 void TransitionFrame::PromoteCallerStackUsingGCRefMap(promote_func* fn, ScanContext* sc, PTR_BYTE pGCRefMap)
1305 WRAPPER_NO_CONTRACT;
1307 GCRefMapDecoder decoder(pGCRefMap);
1311 decoder.ReadStackPop();
1314 TADDR pTransitionBlock = GetTransitionBlock();
1316 while (!decoder.AtEnd())
1318 int pos = decoder.CurrentPos();
1319 int token = decoder.ReadToken();
1324 ofs = (pos < NUM_ARGUMENT_REGISTERS) ?
1325 (TransitionBlock::GetOffsetOfArgumentRegisters() + ARGUMENTREGISTERS_SIZE - (pos + 1) * sizeof(TADDR)) :
1326 (TransitionBlock::GetOffsetOfArgs() + (pos - NUM_ARGUMENT_REGISTERS) * sizeof(TADDR));
1328 ofs = TransitionBlock::GetOffsetOfArgumentRegisters() + pos * sizeof(TADDR);
1331 PTR_TADDR ppObj = dac_cast<PTR_TADDR>(pTransitionBlock + ofs);
1338 fn(dac_cast<PTR_PTR_Object>(ppObj), sc, CHECK_APP_DOMAIN);
1340 case GCREFMAP_INTERIOR:
1341 PromoteCarefully(fn, dac_cast<PTR_PTR_Object>(ppObj), sc, GC_CALL_INTERIOR | GC_CALL_CHECK_APP_DOMAIN);
1343 case GCREFMAP_METHOD_PARAM:
1346 #ifndef DACCESS_COMPILE
1347 MethodDesc *pMDReal = dac_cast<PTR_MethodDesc>(*ppObj);
1348 if (pMDReal != NULL)
1349 GcReportLoaderAllocator(fn, sc, pMDReal->GetLoaderAllocator());
1353 case GCREFMAP_TYPE_PARAM:
1356 #ifndef DACCESS_COMPILE
1357 MethodTable *pMTReal = dac_cast<PTR_MethodTable>(*ppObj);
1358 if (pMTReal != NULL)
1359 GcReportLoaderAllocator(fn, sc, pMTReal->GetLoaderAllocator());
1363 case GCREFMAP_VASIG_COOKIE:
1365 VASigCookie *varArgSig = dac_cast<PTR_VASigCookie>(*ppObj);
1367 //Note: no instantiations needed for varargs
1368 MetaSig msig(varArgSig->signature,
1371 PromoteCallerStackHelper (fn, sc, NULL, &msig);
1375 _ASSERTE(!"Unknown GCREFMAP token");
1381 void PInvokeCalliFrame::PromoteCallerStack(promote_func* fn, ScanContext* sc)
1383 WRAPPER_NO_CONTRACT;
1385 LOG((LF_GC, INFO3, " Promoting CALLI caller Arguments\n" ));
1387 // get the signature
1388 VASigCookie *varArgSig = GetVASigCookie();
1389 if (varArgSig->signature.IsEmpty())
1394 // no instantiations needed for varargs
1395 MetaSig msig(varArgSig->signature,
1398 PromoteCallerStackHelper(fn, sc, NULL, &msig);
1401 #ifndef DACCESS_COMPILE
1402 PInvokeCalliFrame::PInvokeCalliFrame(TransitionBlock * pTransitionBlock, VASigCookie * pVASigCookie, PCODE pUnmanagedTarget)
1403 : FramedMethodFrame(pTransitionBlock, NULL)
1405 LIMITED_METHOD_CONTRACT;
1407 m_pVASigCookie = pVASigCookie;
1408 m_pUnmanagedTarget = pUnmanagedTarget;
1410 #endif // #ifndef DACCESS_COMPILE
1412 #ifdef FEATURE_COMINTEROP
1414 #ifndef DACCESS_COMPILE
1415 ComPlusMethodFrame::ComPlusMethodFrame(TransitionBlock * pTransitionBlock, MethodDesc * pMD)
1416 : FramedMethodFrame(pTransitionBlock, pMD)
1418 LIMITED_METHOD_CONTRACT;
1420 #endif // #ifndef DACCESS_COMPILE
1423 void ComPlusMethodFrame::GcScanRoots(promote_func *fn, ScanContext* sc)
1425 WRAPPER_NO_CONTRACT;
1427 // ComPlusMethodFrame is only used in the event call / late bound call code path where we do not have IL stub
1428 // so we need to promote the arguments and return value manually.
1430 FramedMethodFrame::GcScanRoots(fn, sc);
1431 PromoteCallerStack(fn, sc);
1433 MetaSig::RETURNTYPE returnType = GetFunction()->ReturnsObject();
1435 // Promote the returned object
1436 if(returnType == MetaSig::RETOBJ)
1437 (*fn)(GetReturnObjectPtr(), sc, CHECK_APP_DOMAIN);
1438 else if (returnType == MetaSig::RETBYREF)
1439 PromoteCarefully(fn, GetReturnObjectPtr(), sc, GC_CALL_INTERIOR|CHECK_APP_DOMAIN);
1441 #endif // FEATURE_COMINTEROP
1443 #if defined (_DEBUG) && !defined (DACCESS_COMPILE)
1444 // For IsProtectedByGCFrame, we need to know whether a given object ref is protected
1445 // by a ComPlusMethodFrame or a ComMethodFrame. Since GCScanRoots for those frames are
1446 // quite complicated, we don't want to duplicate their logic so we call GCScanRoots with
1447 // IsObjRefProtected (a fake promote function) and an extended ScanContext to do the checking.
1449 struct IsObjRefProtectedScanContext : public ScanContext
1451 OBJECTREF * oref_to_check;
1452 BOOL oref_protected;
1453 IsObjRefProtectedScanContext (OBJECTREF * oref)
1455 thread_under_crawl = GetThread ();
1457 oref_to_check = oref;
1458 oref_protected = FALSE;
1462 void IsObjRefProtected (Object** ppObj, ScanContext* sc, uint32_t)
1464 LIMITED_METHOD_CONTRACT;
1465 IsObjRefProtectedScanContext * orefProtectedSc = (IsObjRefProtectedScanContext *)sc;
1466 if (ppObj == (Object **)(orefProtectedSc->oref_to_check))
1467 orefProtectedSc->oref_protected = TRUE;
1470 BOOL TransitionFrame::Protects(OBJECTREF * ppORef)
1472 WRAPPER_NO_CONTRACT;
1473 IsObjRefProtectedScanContext sc (ppORef);
1474 // Set the stack limit for the scan to the SP of the managed frame above the transition frame
1475 sc.stack_limit = GetSP();
1476 GcScanRoots (IsObjRefProtected, &sc);
1477 return sc.oref_protected;
1479 #endif //defined (_DEBUG) && !defined (DACCESS_COMPILE)
1481 //+----------------------------------------------------------------------------
1483 // Method: TPMethodFrame::GcScanRoots public
1485 // Synopsis: GC protects arguments on the stack
1489 //+----------------------------------------------------------------------------
1490 #ifdef FEATURE_REMOTING
1492 #ifndef DACCESS_COMPILE
1493 TPMethodFrame::TPMethodFrame(TransitionBlock * pTransitionBlock)
1494 : FramedMethodFrame(pTransitionBlock, NULL)
1496 LIMITED_METHOD_CONTRACT;
1498 #endif // #ifndef DACCESS_COMPILE
1500 void TPMethodFrame::GcScanRoots(promote_func *fn, ScanContext* sc)
1502 WRAPPER_NO_CONTRACT;
1504 // Delegate to FramedMethodFrame
1505 FramedMethodFrame::GcScanRoots(fn, sc);
1506 FramedMethodFrame::PromoteCallerStack(fn, sc);
1508 MetaSig::RETURNTYPE returnType = GetFunction()->ReturnsObject();
1510 // Promote the returned object
1511 if(returnType == MetaSig::RETOBJ)
1513 (*fn)(GetReturnObjectPtr(), sc, CHECK_APP_DOMAIN);
1515 else if (returnType == MetaSig::RETBYREF)
1517 PromoteCarefully(fn, GetReturnObjectPtr(), sc, GC_CALL_INTERIOR|CHECK_APP_DOMAIN);
1523 //+----------------------------------------------------------------------------
1525 // Method: TPMethodFrame::TraceFrame public
1527 // Synopsis: Return where the frame will execute next - the result is filled
1528 // into the given "trace" structure. The frame is responsible for
1529 // detecting where it is in its execution lifetime.
1534 //+----------------------------------------------------------------------------
1535 BOOL TPMethodFrame::TraceFrame(Thread *thread, BOOL fromPatch,
1536 TraceDestination *trace, REGDISPLAY *regs)
1538 WRAPPER_NO_CONTRACT;
1540 // We want to set a frame patch, unless we're already at the
1541 // frame patch, in which case we'll trace stable entrypoint which
1542 // should be set by now.
1546 trace->InitForStub(GetFunction()->GetStableEntryPoint());
1550 #ifdef DACCESS_COMPILE
1553 trace->InitForStub(GetEEFuncEntryPoint(TransparentProxyStubPatchLabel));
1559 #endif // FEATURE_REMOTING
1561 #ifdef FEATURE_COMINTEROP
1564 // Return the # of stack bytes pushed by the unmanaged caller.
1565 UINT ComMethodFrame::GetNumCallerStackBytes()
1567 WRAPPER_NO_CONTRACT;
1570 ComCallMethodDesc* pCMD = PTR_ComCallMethodDesc((TADDR)GetDatum());
1571 PREFIX_ASSUME(pCMD != NULL);
1572 // assumes __stdcall
1573 // compute the callee pop stack bytes
1574 return pCMD->GetNumStackBytes();
1576 #endif // _TARGET_X86_
1578 #ifndef DACCESS_COMPILE
1579 void ComMethodFrame::DoSecondPassHandlerCleanup(Frame * pCurFrame)
1581 LIMITED_METHOD_CONTRACT;
1583 // Find ComMethodFrame, noting any ContextTransitionFrame along the way
1585 while ((pCurFrame != FRAME_TOP) &&
1586 (pCurFrame->GetVTablePtr() != ComMethodFrame::GetMethodFrameVPtr()))
1588 if (pCurFrame->GetVTablePtr() == ContextTransitionFrame::GetMethodFrameVPtr())
1590 // If there is a context transition before we find a ComMethodFrame, do nothing. Expect that
1591 // the AD transition code will perform the corresponding work after it pops its context
1592 // transition frame and before it rethrows the exception.
1595 pCurFrame = pCurFrame->PtrNextFrame();
1598 if (pCurFrame == FRAME_TOP)
1601 ComMethodFrame * pComMethodFrame = (ComMethodFrame *)pCurFrame;
1603 _ASSERTE(pComMethodFrame != NULL);
1604 Thread * pThread = GetThread();
1605 GCX_COOP_THREAD_EXISTS(pThread);
1606 // Unwind the frames till the entry frame (which was ComMethodFrame)
1607 pCurFrame = pThread->GetFrame();
1608 while ((pCurFrame != NULL) && (pCurFrame <= pComMethodFrame))
1610 pCurFrame->ExceptionUnwind();
1611 pCurFrame = pCurFrame->PtrNextFrame();
1614 // At this point, pCurFrame would be the ComMethodFrame's predecessor frame
1615 // that we need to reset to.
1616 _ASSERTE((pCurFrame != NULL) && (pComMethodFrame->PtrNextFrame() == pCurFrame));
1617 pThread->SetFrame(pCurFrame);
1619 #endif // !DACCESS_COMPILE
1621 #endif // FEATURE_COMINTEROP
1626 PTR_UMEntryThunk UMThkCallFrame::GetUMEntryThunk()
1628 LIMITED_METHOD_DAC_CONTRACT;
1629 return dac_cast<PTR_UMEntryThunk>(GetDatum());
1632 #ifdef DACCESS_COMPILE
1633 void UMThkCallFrame::EnumMemoryRegions(CLRDataEnumMemoryFlags flags)
1635 WRAPPER_NO_CONTRACT;
1636 UnmanagedToManagedFrame::EnumMemoryRegions(flags);
1638 // Pieces of the UMEntryThunk need to be saved.
1639 UMEntryThunk *pThunk = GetUMEntryThunk();
1640 DacEnumMemoryRegion(dac_cast<TADDR>(pThunk), sizeof(UMEntryThunk));
1642 UMThunkMarshInfo *pMarshInfo = pThunk->GetUMThunkMarshInfo();
1643 DacEnumMemoryRegion(dac_cast<TADDR>(pMarshInfo), sizeof(UMThunkMarshInfo));
1647 #endif // _TARGET_X86_
1649 #ifndef DACCESS_COMPILE
1651 #if defined(_MSC_VER) && defined(_TARGET_X86_)
1652 #pragma optimize("y", on) // Small critical routines, don't put in EBP frame
1655 // Initialization of HelperMethodFrame.
1656 void HelperMethodFrame::Push()
1659 if (m_Attribs & FRAME_ATTR_NO_THREAD_ABORT) NOTHROW; else THROWS;
1666 // Finish initialization
1669 // Compiler would not inline GetGSCookiePtr() because of it is virtual method.
1670 // Inline it manually and verify that it gives same result.
1671 _ASSERTE(GetGSCookiePtr() == (((GSCookie *)(this)) - 1));
1672 *(((GSCookie *)(this)) - 1) = GetProcessGSCookie();
1674 _ASSERTE(!m_MachState.isValid());
1676 Thread * pThread = ::GetThread();
1677 m_pThread = pThread;
1680 Frame::Push(pThread);
1682 if (!pThread->HasThreadStateOpportunistic((Thread::ThreadState)(Thread::TS_YieldRequested | Thread::TS_AbortRequested)))
1685 // Outline the slow path for better perf
1689 void HelperMethodFrame::Pop()
1692 if (m_Attribs & FRAME_ATTR_NO_THREAD_ABORT) NOTHROW; else THROWS;
1698 Thread * pThread = m_pThread;
1700 if ((m_Attribs & FRAME_ATTR_NO_THREAD_ABORT) || !pThread->HasThreadStateOpportunistic(Thread::TS_AbortInitiated))
1702 Frame::Pop(pThread);
1706 // Outline the slow path for better perf
1710 #if defined(_MSC_VER) && defined(_TARGET_X86_)
1711 #pragma optimize("", on) // Go back to command line default optimizations
1714 NOINLINE void HelperMethodFrame::PushSlowHelper()
1717 if (m_Attribs & FRAME_ATTR_NO_THREAD_ABORT) NOTHROW; else THROWS;
1723 if (!(m_Attribs & FRAME_ATTR_NO_THREAD_ABORT))
1725 if (m_pThread->IsAbortRequested())
1727 m_pThread->HandleThreadAbort();
1732 if (m_pThread->IsYieldRequested())
1734 __SwitchToThread(0, CALLER_LIMITS_SPINNING);
1738 NOINLINE void HelperMethodFrame::PopSlowHelper()
1747 m_pThread->HandleThreadAbort();
1748 Frame::Pop(m_pThread);
1751 #endif // #ifndef DACCESS_COMPILE
1753 MethodDesc* HelperMethodFrame::GetFunction()
1755 WRAPPER_NO_CONTRACT;
1757 #ifndef DACCESS_COMPILE
1758 InsureInit(false, NULL);
1761 if (m_MachState.isValid())
1767 return ECall::MapTargetBackToMethod(m_FCallEntry);
1772 //---------------------------------------------------------------------------------------
1774 // Ensures the HelperMethodFrame gets initialized, if not already.
1778 // * true: ensure the simple, first stage of initialization has been completed.
1779 // This is used when the HelperMethodFrame is first created.
1780 // * false: complete any initialization that was left to do, if any.
1781 // * unwindState - [out] DAC builds use this to return the unwound machine state.
1782 // * hostCallPreference - (See code:HelperMethodFrame::HostCallPreference.)
1785 // Normally, the function always returns TRUE meaning the initialization succeeded.
1787 // However, if hostCallPreference is NoHostCalls, AND if a callee (like
1788 // LazyMachState::unwindLazyState) needed to acquire a JIT reader lock and was unable
1789 // to do so (lest it re-enter the host), then InsureInit will abort and return FALSE.
1790 // So any callers that specify hostCallPreference = NoHostCalls (which is not the
1791 // default), should check for FALSE return, and refuse to use the HMF in that case.
1792 // Currently only asynchronous calls made by profilers use that code path.
1795 BOOL HelperMethodFrame::InsureInit(bool initialInit,
1796 MachState * unwindState,
1797 HostCallPreference hostCallPreference /* = AllowHostCalls */)
1803 if ((hostCallPreference == AllowHostCalls) && !m_MachState.isValid()) { HOST_CALLS; } else { HOST_NOCALLS; }
1807 if (m_MachState.isValid())
1812 _ASSERTE(m_Attribs != 0xCCCCCCCC);
1814 #ifndef DACCESS_COMPILE
1817 m_pMD = ECall::MapTargetBackToMethod(m_FCallEntry);
1819 // if this is an FCall, we should find it
1820 _ASSERTE(m_FCallEntry == 0 || m_pMD != 0);
1824 // Because TRUE FCalls can be called from via reflection, com-interop, etc.,
1825 // we can't rely on the fact that we are called from jitted code to find the
1826 // caller of the FCALL. Thus FCalls must erect the frame directly in the
1827 // FCall. For JIT helpers, however, we can rely on this, and so they can
1828 // be sneakier and defer the HelperMethodFrame setup to a called worker method.
1830 // Work with a copy so that we only write the values once.
1831 // this avoids race conditions.
1832 LazyMachState* lazy = &m_MachState;
1833 DWORD threadId = m_pThread->GetOSThreadId();
1837 m_FCallEntry == 0 &&
1838 !(m_Attribs & Frame::FRAME_ATTR_EXACT_DEPTH)) // Jit Helper
1840 LazyMachState::unwindLazyState(
1845 hostCallPreference);
1847 #if !defined(DACCESS_COMPILE)
1848 if (!unwound.isValid())
1850 // This only happens if LazyMachState::unwindLazyState had to abort as a
1851 // result of failing to take a reader lock (because we told it not to yield,
1852 // but the writer lock was already held). Since we've not yet updated
1853 // m_MachState, this HelperMethodFrame will still be considered not fully
1854 // initialized (so a future call into InsureInit() will attempt to complete
1855 // initialization again).
1857 // Note that, in DAC builds, the contract with LazyMachState::unwindLazyState
1858 // is a bit different, and it's expected that LazyMachState::unwindLazyState
1859 // will commonly return an unwound state with _pRetAddr==NULL (which counts
1860 // as an "invalid" MachState). So have DAC builds deliberately fall through
1861 // rather than aborting when unwound is invalid.
1862 _ASSERTE(hostCallPreference == NoHostCalls);
1865 #endif // !defined(DACCESS_COMPILE)
1867 else if (!initialInit &&
1868 (m_Attribs & Frame::FRAME_ATTR_CAPTURE_DEPTH_2) != 0)
1870 // explictly told depth
1871 LazyMachState::unwindLazyState(lazy, &unwound, threadId, 2);
1876 LazyMachState::unwindLazyState(lazy, &unwound, threadId, 1);
1879 _ASSERTE(unwound.isValid());
1881 #if !defined(DACCESS_COMPILE)
1882 lazy->setLazyStateFromUnwind(&unwound);
1883 #else // DACCESS_COMPILE
1886 *unwindState = unwound;
1888 #endif // DACCESS_COMPILE
1894 #include "comdelegate.h"
1896 Assembly* SecureDelegateFrame::GetAssembly()
1898 WRAPPER_NO_CONTRACT;
1900 #if !defined(DACCESS_COMPILE)
1901 // obtain the frame off the delegate pointer
1902 DELEGATEREF delegate = (DELEGATEREF) GetThis();
1904 if (!delegate->IsWrapperDelegate())
1906 MethodDesc* pMethod = (MethodDesc*) delegate->GetMethodPtrAux();
1907 Assembly* pAssembly = pMethod->GetAssembly();
1908 _ASSERTE(pAssembly != NULL);
1919 BOOL SecureDelegateFrame::TraceFrame(Thread *thread, BOOL fromPatch, TraceDestination *trace, REGDISPLAY *regs)
1921 WRAPPER_NO_CONTRACT;
1923 _ASSERTE(!fromPatch);
1925 // Unlike multicast delegates, secure delegates only call one method. So, we should just return false here
1926 // and let the step out logic continue to the caller of the secure delegate stub.
1927 LOG((LF_CORDB, LL_INFO1000, "SDF::TF: return FALSE\n"));
1932 BOOL MulticastFrame::TraceFrame(Thread *thread, BOOL fromPatch,
1933 TraceDestination *trace, REGDISPLAY *regs)
1943 _ASSERTE(!fromPatch);
1945 #ifdef DACCESS_COMPILE
1948 #else // !DACCESS_COMPILE
1949 LOG((LF_CORDB,LL_INFO10000, "MulticastFrame::TF FromPatch:0x%x, at 0x%x\n", fromPatch, GetControlPC(regs)));
1951 // At this point we have no way to recover the Stub object from the control pc. We can't use the MD stored
1952 // in the MulticastFrame because it points to the dummy Invoke() method, not the method we want to call.
1955 int delegateCount = 0;
1957 #if defined(_TARGET_X86_)
1958 // At this point the counter hasn't been incremented yet.
1959 delegateCount = *regs->pEdi + 1;
1960 pbDel = *(BYTE **)( (size_t)*(regs->pEsi) + GetOffsetOfTransitionBlock() + ArgIterator::GetThisOffset());
1961 #elif defined(_TARGET_AMD64_)
1962 // At this point the counter hasn't been incremented yet.
1963 delegateCount = (int)regs->pCurrentContext->Rdi + 1;
1964 pbDel = *(BYTE **)( (size_t)(regs->pCurrentContext->Rsi) + GetOffsetOfTransitionBlock() + ArgIterator::GetThisOffset());
1965 #elif defined(_TARGET_ARM_)
1966 // At this point the counter has not yet been incremented. Counter is in R7, frame pointer in R4.
1967 delegateCount = regs->pCurrentContext->R7 + 1;
1968 pbDel = *(BYTE **)( (size_t)(regs->pCurrentContext->R4) + GetOffsetOfTransitionBlock() + ArgIterator::GetThisOffset());
1971 PORTABILITY_ASSERT("MulticastFrame::TraceFrame (frames.cpp)");
1974 int totalDelegateCount = (int)*(size_t*)(pbDel + DelegateObject::GetOffsetOfInvocationCount());
1976 _ASSERTE( COMDelegate::IsTrueMulticastDelegate( ObjectToOBJECTREF((Object*)pbDel) ) );
1978 if (delegateCount == totalDelegateCount)
1980 LOG((LF_CORDB, LL_INFO1000, "MF::TF: Executed all stubs, should return\n"));
1981 // We've executed all the stubs, so we should return
1986 // We're going to execute stub delegateCount next, so go and grab it.
1987 BYTE *pbDelInvocationList = *(BYTE **)(pbDel + DelegateObject::GetOffsetOfInvocationList());
1989 pbDel = *(BYTE**)( ((ArrayBase *)pbDelInvocationList)->GetDataPtr() +
1990 ((ArrayBase *)pbDelInvocationList)->GetComponentSize()*delegateCount);
1993 return DelegateInvokeStubManager::TraceDelegateObject(pbDel, trace);
1995 #endif // !DACCESS_COMPILE
1998 #ifndef DACCESS_COMPILE
2000 VOID InlinedCallFrame::Init()
2002 WRAPPER_NO_CONTRACT;
2004 *((TADDR *)this) = GetMethodFrameVPtr();
2006 // GetGSCookiePtr contains a virtual call and this is a perf critical method so we don't want to call it in ret builds
2007 GSCookie *ptrGS = (GSCookie *)((BYTE *)this - sizeof(GSCookie));
2008 _ASSERTE(ptrGS == GetGSCookiePtr());
2010 *ptrGS = GetProcessGSCookie();
2013 m_pCallSiteSP = NULL;
2014 m_pCallerReturnAddress = NULL;
2017 #if defined(_WIN64) && !defined(FEATURE_PAL)
2019 EXTERN_C void PInvokeStubForHostInner(DWORD dwStackSize, LPVOID pStackFrame, LPVOID pTarget);
2021 // C++ piece of one static stub for host on 64-bit. This is called by PInvokeStubForHost (PInvokeStubs.asm).
2022 void __stdcall PInvokeStubForHostWorker(DWORD dwStackSize, LPVOID pStackFrame, LPVOID pThis)
2032 InlinedCallFrame *pFrame = (InlinedCallFrame *)GetThread()->GetFrame();
2033 _ASSERTE(InlinedCallFrame::FrameHasActiveCall(pFrame));
2035 LPVOID pTarget = NULL;
2036 MethodDesc *pMD = pFrame->GetFunction();
2040 // This is a CALLI and m_Datum is a mangled target
2041 pTarget = (LPVOID)((UINT_PTR)pFrame->m_Datum >> 1);
2043 else if (pMD->IsNDirect())
2045 pTarget = ((NDirectMethodDesc *)pMD)->ndirect.m_pNativeNDirectTarget;
2048 #ifdef FEATURE_STACK_PROBE
2049 // We need just the stack probe for QCalls
2050 RetailStackProbe(ADJUST_PROBE(DEFAULT_ENTRY_PROBE_AMOUNT));
2052 PInvokeStubForHostInner(dwStackSize, pStackFrame, pTarget);
2056 #ifdef FEATURE_COMINTEROP
2057 else if (pMD->IsComPlusCall() || pMD->IsEEImpl())
2059 LPVOID *lpVtbl = *(LPVOID **)pThis;
2060 ComPlusCallInfo *pComPlusCallInfo = ComPlusCallInfo::FromMethodDesc(pMD);
2061 pTarget = lpVtbl[pComPlusCallInfo->m_cachedComSlot];
2063 #endif // FEATURE_COMINTEROP
2066 UNREACHABLE_MSG("Unexpected MethodDesc kind encountered in PInvokeStubForHostWorker");
2069 // We ask the host on every call. This is different from x86 but we keep this
2070 // behavior for maximum compatibility with previous releases.
2071 if (CallNeedsHostHook((size_t)pTarget))
2073 // call LeaveRuntime
2074 class LeaveRuntimeHolderThrowComplus
2077 LeaveRuntimeHolderThrowComplus(size_t target)
2079 Thread::LeaveRuntimeThrowComplus(target);
2081 ~LeaveRuntimeHolderThrowComplus()
2083 Thread::EnterRuntime();
2085 } holder((size_t)pTarget);
2087 PInvokeStubForHostInner(dwStackSize, pStackFrame, pTarget);
2088 // ~LeaveRuntimeHolderThrowComplus calls EnterRuntime here
2092 // The host doesn't want to be notified - just call the target
2093 PInvokeStubForHostInner(dwStackSize, pStackFrame, pTarget);
2096 #endif // _WIN64 && !FEATURE_PAL
2100 void UnmanagedToManagedFrame::ExceptionUnwind()
2102 WRAPPER_NO_CONTRACT;
2104 AppDomain::ExceptionUnwind(this);
2107 #endif // !DACCESS_COMPILE
2109 void ContextTransitionFrame::GcScanRoots(promote_func *fn, ScanContext* sc)
2111 WRAPPER_NO_CONTRACT;
2113 // Don't check app domains here - m_ReturnExecutionContext is in the parent frame's app domain
2114 (*fn)(dac_cast<PTR_PTR_Object>(PTR_HOST_MEMBER_TADDR(ContextTransitionFrame, this, m_ReturnExecutionContext)), sc, 0);
2115 LOG((LF_GC, INFO3, " " FMT_ADDR "\n", DBG_ADDR(m_ReturnExecutionContext) ));
2117 // Don't check app domains here - m_LastThrownObjectInParentContext is in the parent frame's app domain
2118 (*fn)(dac_cast<PTR_PTR_Object>(PTR_HOST_MEMBER_TADDR(ContextTransitionFrame, this, m_LastThrownObjectInParentContext)), sc, 0);
2119 LOG((LF_GC, INFO3, " " FMT_ADDR "\n", DBG_ADDR(m_LastThrownObjectInParentContext) ));
2121 // don't need to worry about the object moving as it is stored in a weak handle
2122 // but do need to report it so it doesn't get collected if the only reference to
2123 // it is in this frame. So only do something if are in promotion phase. And if are
2124 // in reloc phase this could cause invalid refs as the object may have been moved.
2125 if (! sc->promotion)
2128 // The dac only cares about strong references at the moment. Since this is always
2129 // in a weak ref, we don't report it here.
2130 #if defined(FEATURE_REMOTING) && !defined(DACCESS_COMPILE)
2131 Context *returnContext = GetReturnContext();
2132 PREFIX_ASSUME(returnContext != NULL);
2133 _ASSERTE(returnContext);
2134 _ASSERTE(returnContext->GetDomain()); // this will make sure is a valid pointer
2136 // In the VM we operate on a local to avoid double relocation. In the dac we actually want
2137 // to know the real location.
2138 #ifdef DACCESS_COMPILE
2139 PTR_PTR_Object ppRef = returnContext->GetExposedObjectRawUncheckedPtr();
2144 (*fn)(ppRef, sc, 0);
2146 #else // DACCESS_COMPILE
2147 // We are in the middle of the GC. OBJECTREFs can't be used here since their built-in validation
2148 // chokes on objects that have been relocated already
2149 Object *pRef = returnContext->GetExposedObjectRawUnchecked();
2154 LOG((LF_GC, INFO3, "ContextTransitionFrame Protection Frame Promoting" FMT_ADDR "to ", DBG_ADDR(pRef) ));
2155 // Don't check app domains here - the objects are in the parent frame's app domain
2157 (*fn)(&pRef, sc, 0);
2158 LOG((LF_GC, INFO3, FMT_ADDR "\n", DBG_ADDR(pRef)));
2159 #endif // !DACCESS_COMPILE
2165 PCODE UnmanagedToManagedFrame::GetReturnAddress()
2167 WRAPPER_NO_CONTRACT;
2169 PCODE pRetAddr = Frame::GetReturnAddress();
2171 if (InlinedCallFrame::FrameHasActiveCall(m_Next) &&
2172 pRetAddr == m_Next->GetReturnAddress())
2174 // there's actually no unmanaged code involved - we were called directly
2175 // from managed code using an InlinedCallFrame