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.
8 // These C++ classes expose activation frames to the rest of the EE.
9 // Activation frames are actually created by JIT-generated or stub-generated
10 // code on the machine stack. Thus, the layout of the Frame classes and
11 // the JIT/Stub code generators are tightly interwined.
13 // IMPORTANT: Since frames are not actually constructed by C++,
14 // don't try to define constructor/destructor functions. They won't get
17 // IMPORTANT: Not all methods have full-fledged activation frames (in
18 // particular, the JIT may create frameless methods.) This is one reason
19 // why Frame doesn't expose a public "Next()" method: such a method would
20 // skip frameless method calls. You must instead use one of the
24 // The following is the hierarchy of frames:
26 // Frame - the root class. There are no actual instances
29 // +-GCFrame - this frame doesn't represent a method call.
30 // | it's sole purpose is to let the EE gc-protect
31 // | object references that it is manipulating.
33 // +- FaultingExceptionFrame - this frame was placed on a method which faulted
34 // | to save additional state information
38 // +-HijackFrame - if a method's return address is hijacked, we
39 // | construct one of these to allow crawling back
40 // | to where the return should have gone.
42 // +-ResumableFrame - this abstract frame provides the context necessary to
43 // | | allow garbage collection during handling of
44 // | | a resumable exception (e.g. during edit-and-continue,
45 // | | or under GCStress4).
47 // | +-RedirectedThreadFrame - this frame is used for redirecting threads during suspension
49 #endif // FEATURE_HIJACK
53 // +-InlinedCallFrame - if a call to unmanaged code is hoisted into
54 // | a JIT'ted caller, the calling method keeps
55 // | this frame linked throughout its activation.
57 // +-HelperMethodFrame - frame used allow stack crawling inside jit helpers and fcalls
59 // + +-HelperMethodFrame_1OBJ- reports additional object references
61 // + +-HelperMethodFrame_2OBJ- reports additional object references
63 // + +-HelperMethodFrame_PROTECTOBJ - reports additional object references
65 // +-TransitionFrame - this abstract frame represents a transition from
66 // | | one or more nested frameless method calls
67 // | | to either a EE runtime helper function or
68 // | | a framed method.
70 // | +-StubHelperFrame - for instantiating stubs that need to grow stack arguments
72 // | +-SecureDelegateFrame - represents a call Delegate.Invoke for secure delegate
74 // | +-MulticastFrame - this frame protects arguments to a MulticastDelegate
75 // | Invoke() call while calling each subscriber.
77 // | +-FramedMethodFrame - this abstract frame represents a call to a method
78 // | | that generates a full-fledged frame.
80 #ifdef FEATURE_COMINTEROP
82 // | +-ComPlusMethodFrame - represents a CLR to COM call using the generic worker
84 #endif //FEATURE_COMINTEROP
86 // | +-PInvokeCalliFrame - protects arguments when a call to GetILStubForCalli is made
87 // | | to get or create IL stub for an unmanaged CALLI
89 // | +-PrestubMethodFrame - represents a call to a prestub
91 // | +-StubDispatchFrame - represents a call into the virtual call stub manager
94 // | +-ExternalMethodFrame - represents a call from an ExternalMethdThunk
96 // | +-TPMethodFrame - for calls on transparent proxy
98 // +-UnmanagedToManagedFrame - this frame represents a transition from
99 // | | unmanaged code back to managed code. It's
100 // | | main functions are to stop COM+ exception
101 // | | propagation and to expose unmanaged parameters.
103 #ifdef FEATURE_COMINTEROP
105 // | +-ComMethodFrame - this frame represents a transition from
108 // | +-ComPrestubMethodFrame - prestub frame for calls from COM to CLR
110 #endif //FEATURE_COMINTEROP
112 // | +-UMThkCallFrame - this frame represents an unmanaged->managed
113 // | transition through N/Direct
116 // +-ContextTransitionFrame - this frame is used to mark an appdomain transition
119 // +-TailCallFrame - padding for tailcalls
121 // +-ProtectByRefsFrame
123 // +-ProtectValueClassFrame
125 // +-DebuggerClassInitMarkFrame - marker frame to indicate that "class init" code is running
127 // +-DebuggerSecurityCodeMarkFrame - marker frame to indicate that security code is running
129 // +-DebuggerExitFrame - marker frame to indicate that a "break" IL instruction is being executed
131 // +-DebuggerU2MCatchHandlerFrame - marker frame to indicate that native code is going to catch and
132 // | swallow a managed exception
134 #ifdef DEBUGGING_SUPPORTED
135 // +-FuncEvalFrame - frame for debugger function evaluation
136 #endif // DEBUGGING_SUPPORTED
139 // +-ExceptionFilterFrame - this frame wraps call to exception filter
141 // +-SecurityContextFrame - place the security context of an assembly on the stack to ensure it will be included in security demands
143 //------------------------------------------------------------------------
145 //------------------------------------------------------------------------
147 This is the list of Interop stubs & transition helpers with information
148 regarding what (if any) Frame they used and where they were set up:
151 JIT inlined: The code to call the method is inlined into the caller by the JIT.
152 InlinedCallFrame is erected by the JITted code.
153 Requires marshaling: The stub does not erect any frames explicitly but contains
154 an unmanaged CALLI which turns it into the JIT inlined case.
156 Delegate over a native function pointer:
157 The same as P/Invoke but the raw JIT inlined case is not present (the call always
158 goes through an IL stub).
161 The same as P/Invoke.
162 PInvokeCalliFrame is erected in stub generated by GenerateGetStubForPInvokeCalli
163 before calling to GetILStubForCalli which generates the IL stub. This happens only
164 the first time a call via the corresponding VASigCookie is made.
167 Late-bound or eventing: The stub is generated by GenerateGenericComplusWorker
168 (x86) or exists statically as GenericComPlusCallStub[RetBuffArg] (64-bit),
169 and it erects a ComPlusMethodFrame frame.
170 Early-bound: The stub does not erect any frames explicitly but contains an
171 unmanaged CALLI which turns it into the JIT inlined case.
175 Interpreted: The stub is generated by ComCall::CreateGenericComCallStub
176 (in ComToClrCall.cpp) and it erects a ComMethodFrame frame.
178 The prestub is ComCallPreStub (in ComCallableWrapper.cpp) and it erects
179 a ComPrestubMethodFrame frame.
181 Reverse P/Invoke (used for C++ exports & fixups as well as delegates
182 obtained from function pointers):
184 x86: The stub is generated by UMEntryThunk::CompileUMThunkWorker
185 (in DllImportCallback.cpp) and it is frameless. It calls directly
186 the managed target or to IL stub if marshaling is required.
187 non-x86: The stub exists statically as UMThunkStub and calls to IL stub.
189 The prestub is generated by GenerateUMThunkPrestub (x86) or exists statically
190 as TheUMEntryPrestub (64-bit), and it erects an UMThkCallFrame frame.
192 Reverse P/Invoke AppDomain selector stub:
193 The asm helper is IJWNOADThunkJumpTarget (in asmhelpers.asm) and it is frameless.
195 //------------------------------------------------------------------------
197 //------------------------------------------------------------------------
199 #ifndef FRAME_ABSTRACT_TYPE_NAME
200 #define FRAME_ABSTRACT_TYPE_NAME(frameType)
202 #ifndef FRAME_TYPE_NAME
203 #define FRAME_TYPE_NAME(frameType)
206 FRAME_ABSTRACT_TYPE_NAME(FrameBase)
207 FRAME_ABSTRACT_TYPE_NAME(Frame)
208 FRAME_ABSTRACT_TYPE_NAME(TransitionFrame)
209 #ifdef FEATURE_HIJACK
210 FRAME_TYPE_NAME(ResumableFrame)
211 FRAME_TYPE_NAME(RedirectedThreadFrame)
212 #endif // FEATURE_HIJACK
213 FRAME_TYPE_NAME(FaultingExceptionFrame)
214 #ifdef DEBUGGING_SUPPORTED
215 FRAME_TYPE_NAME(FuncEvalFrame)
216 #endif // DEBUGGING_SUPPORTED
217 FRAME_TYPE_NAME(HelperMethodFrame)
218 FRAME_TYPE_NAME(HelperMethodFrame_1OBJ)
219 FRAME_TYPE_NAME(HelperMethodFrame_2OBJ)
220 FRAME_TYPE_NAME(HelperMethodFrame_PROTECTOBJ)
221 FRAME_ABSTRACT_TYPE_NAME(FramedMethodFrame)
222 FRAME_TYPE_NAME(SecureDelegateFrame)
223 FRAME_TYPE_NAME(MulticastFrame)
224 FRAME_ABSTRACT_TYPE_NAME(UnmanagedToManagedFrame)
225 #ifdef FEATURE_COMINTEROP
226 FRAME_TYPE_NAME(ComMethodFrame)
227 FRAME_TYPE_NAME(ComPlusMethodFrame)
228 FRAME_TYPE_NAME(ComPrestubMethodFrame)
229 #endif // FEATURE_COMINTEROP
230 FRAME_TYPE_NAME(PInvokeCalliFrame)
231 #ifdef FEATURE_HIJACK
232 FRAME_TYPE_NAME(HijackFrame)
233 #endif // FEATURE_HIJACK
234 FRAME_TYPE_NAME(PrestubMethodFrame)
235 FRAME_TYPE_NAME(StubDispatchFrame)
236 FRAME_TYPE_NAME(ExternalMethodFrame)
237 #ifdef FEATURE_READYTORUN
238 FRAME_TYPE_NAME(DynamicHelperFrame)
240 #if !defined(_TARGET_X86_)
241 FRAME_TYPE_NAME(StubHelperFrame)
243 FRAME_TYPE_NAME(GCFrame)
244 #ifdef FEATURE_INTERPRETER
245 FRAME_TYPE_NAME(InterpreterFrame)
246 #endif // FEATURE_INTERPRETER
247 FRAME_TYPE_NAME(ProtectByRefsFrame)
248 FRAME_TYPE_NAME(ProtectValueClassFrame)
249 FRAME_TYPE_NAME(DebuggerClassInitMarkFrame)
250 FRAME_TYPE_NAME(DebuggerSecurityCodeMarkFrame)
251 FRAME_TYPE_NAME(DebuggerExitFrame)
252 FRAME_TYPE_NAME(DebuggerU2MCatchHandlerFrame)
254 FRAME_TYPE_NAME(UMThkCallFrame)
256 FRAME_TYPE_NAME(InlinedCallFrame)
257 FRAME_TYPE_NAME(ContextTransitionFrame)
258 FRAME_TYPE_NAME(TailCallFrame)
259 FRAME_TYPE_NAME(ExceptionFilterFrame)
261 FRAME_TYPE_NAME(AssumeByrefFromJITStack)
263 FRAME_TYPE_NAME(SecurityContextFrame)
265 #undef FRAME_ABSTRACT_TYPE_NAME
266 #undef FRAME_TYPE_NAME
268 //------------------------------------------------------------------------
272 #if defined(_MSC_VER) && defined(_TARGET_X86_) && !defined(FPO_ON)
273 #pragma optimize("y", on) // Small critical routines, don't put in EBP frame
275 #define FRAMES_TURNED_FPO_ON 1
282 #include "objecthandle.h"
284 #include "siginfo.hpp"
287 #include "method.hpp"
288 #include "stackwalk.h"
292 #include "callingconvention.h"
294 // Forward references
296 class FieldMarshaler;
297 class FramedMethodFrame;
298 typedef VPTR(class FramedMethodFrame) PTR_FramedMethodFrame;
301 class UMThunkMarshInfo;
303 struct ResolveCacheElem;
304 #if defined(DACCESS_COMPILE)
305 class DacDbiInterfaceImpl;
306 #endif // DACCESS_COMPILE
307 #ifdef FEATURE_COMINTEROP
308 class ComMethodFrame;
309 class ComCallMethodDesc;
310 #endif // FEATURE_COMINTEROP
312 // Note: the value (-1) is used to generate the largest possible pointer value: this keeps frame addresses
313 // increasing upward. Because we want to ensure that we don't accidentally change this, we have a C_ASSERT
314 // in stackwalk.cpp. Since it requires constant values as args, we need to define FRAME_TOP in two steps.
315 // First we define FRAME_TOP_VALUE which we'll use when we do the compile-time check, then we'll define
316 // FRAME_TOP in terms of FRAME_TOP_VALUE. Defining FRAME_TOP as a PTR_Frame means we don't have to type cast
317 // whenever we compare it to a PTR_Frame value (the usual use of the value).
318 #define FRAME_TOP_VALUE ~0 // we want to say -1 here, but gcc has trouble with the signed value
319 #define FRAME_TOP (PTR_Frame(FRAME_TOP_VALUE))
321 #ifndef DACCESS_COMPILE
323 #if defined(FEATURE_PAL) && !defined(CROSSGEN_COMPILE)
325 #define DEFINE_DTOR(klass) \
327 virtual ~klass() { PopIfChained(); }
331 #define DEFINE_DTOR(klass)
333 #endif // FEATURE_PAL && !CROSSGEN_COMPILE
335 #define DEFINE_VTABLE_GETTER(klass) \
337 static TADDR GetMethodFrameVPtr() { \
338 LIMITED_METHOD_CONTRACT; \
339 klass boilerplate(false); \
340 return *((TADDR*)&boilerplate); \
342 klass(bool dummy) { LIMITED_METHOD_CONTRACT; }
344 #define DEFINE_VTABLE_GETTER_AND_DTOR(klass) \
345 DEFINE_VTABLE_GETTER(klass) \
348 #define DEFINE_VTABLE_GETTER_AND_CTOR(klass) \
349 DEFINE_VTABLE_GETTER(klass) \
351 klass() { LIMITED_METHOD_CONTRACT; }
353 #define DEFINE_VTABLE_GETTER_AND_CTOR_AND_DTOR(klass) \
354 DEFINE_VTABLE_GETTER_AND_DTOR(klass) \
356 klass() { LIMITED_METHOD_CONTRACT; }
360 #define DEFINE_VTABLE_GETTER(klass) \
362 static TADDR GetMethodFrameVPtr() { \
363 LIMITED_METHOD_CONTRACT; \
364 return klass::VPtrTargetVTable(); \
367 #define DEFINE_VTABLE_GETTER_AND_DTOR(klass) \
368 DEFINE_VTABLE_GETTER(klass) \
370 #define DEFINE_VTABLE_GETTER_AND_CTOR(klass) \
371 DEFINE_VTABLE_GETTER(klass) \
373 #define DEFINE_VTABLE_GETTER_AND_CTOR_AND_DTOR(klass) \
374 DEFINE_VTABLE_GETTER_AND_CTOR(klass) \
376 #endif // #ifndef DACCESS_COMPILE
378 //-----------------------------------------------------------------------------
379 // For reporting on types of frames at runtime.
386 typedef DPTR(FrameTypeName) PTR_FrameTypeName;
388 //-----------------------------------------------------------------------------
389 // Frame depends on the location of its vtable within the object. This
390 // superclass ensures that the vtable for Frame objects is in the same
391 // location under both MSVC and GCC.
392 //-----------------------------------------------------------------------------
396 VPTR_BASE_VTABLE_CLASS(FrameBase)
399 FrameBase() {LIMITED_METHOD_CONTRACT; }
401 virtual void GcScanRoots(promote_func *fn, ScanContext* sc) {
402 LIMITED_METHOD_CONTRACT;
403 // Nothing to protect
406 #ifdef DACCESS_COMPILE
407 virtual void EnumMemoryRegions(CLRDataEnumMemoryFlags flags) = 0;
411 //------------------------------------------------------------------------
412 // Frame defines methods common to all frame types. There are no actual
413 // instances of root frames.
414 //------------------------------------------------------------------------
416 class Frame : public FrameBase
418 friend class CheckAsmOffsets;
419 #ifdef DACCESS_COMPILE
420 friend void Thread::EnumMemoryRegions(CLRDataEnumMemoryFlags flags);
423 VPTR_ABSTRACT_VTABLE_CLASS(Frame, FrameBase)
427 //------------------------------------------------------------------------
428 // Special characteristics of a frame
429 //------------------------------------------------------------------------
432 FRAME_ATTR_EXCEPTION = 1, // This frame caused an exception
433 FRAME_ATTR_OUT_OF_LINE = 2, // The exception out of line (IP of the frame is not correct)
434 FRAME_ATTR_FAULTED = 4, // Exception caused by Win32 fault
435 FRAME_ATTR_RESUMABLE = 8, // We may resume from this frame
436 FRAME_ATTR_CAPTURE_DEPTH_2 = 0x10, // This is a helperMethodFrame and the capture occurred at depth 2
437 FRAME_ATTR_EXACT_DEPTH = 0x20, // This is a helperMethodFrame and a jit helper, but only crawl to the given depth
438 FRAME_ATTR_NO_THREAD_ABORT = 0x40, // This is a helperMethodFrame that should not trigger thread aborts on entry
440 virtual unsigned GetFrameAttribs()
442 LIMITED_METHOD_DAC_CONTRACT;
443 return FRAME_ATTR_NONE;
446 //------------------------------------------------------------------------
447 // Performs cleanup on an exception unwind
448 //------------------------------------------------------------------------
449 #ifndef DACCESS_COMPILE
450 virtual void ExceptionUnwind()
452 // Nothing to do here.
453 LIMITED_METHOD_CONTRACT;
457 // Should be overridden to return TRUE if the frame contains register
458 // state of the caller.
459 virtual BOOL NeedsUpdateRegDisplay()
464 //------------------------------------------------------------------------
465 // Is this a frame used on transition to native code from jitted code?
466 //------------------------------------------------------------------------
467 virtual BOOL IsTransitionToNativeFrame()
469 LIMITED_METHOD_CONTRACT;
473 virtual MethodDesc *GetFunction()
475 LIMITED_METHOD_DAC_CONTRACT;
479 virtual Assembly *GetAssembly()
482 MethodDesc *pMethod = GetFunction();
484 return pMethod->GetModule()->GetAssembly();
489 // indicate the current X86 IP address within the current method
490 // return 0 if the information is not available
491 virtual const PTR_BYTE GetIP()
493 LIMITED_METHOD_CONTRACT;
497 // DACCESS: GetReturnAddressPtr should return the
498 // target address of the return address in the frame.
499 virtual TADDR GetReturnAddressPtr()
501 LIMITED_METHOD_DAC_CONTRACT;
505 virtual PCODE GetReturnAddress()
508 TADDR ptr = GetReturnAddressPtr();
509 return (ptr != NULL) ? *PTR_PCODE(ptr) : NULL;
512 virtual PTR_Context* GetReturnContextAddr()
514 LIMITED_METHOD_DAC_CONTRACT;
518 Context *GetReturnContext()
522 PTR_Context* ppReturnContext = GetReturnContextAddr();
523 if (! ppReturnContext)
525 return *ppReturnContext;
528 AppDomain *GetReturnDomain()
533 if (! GetReturnContext())
535 return GetReturnContext()->GetDomain();
538 #ifndef DACCESS_COMPILE
539 virtual Object **GetReturnExecutionContextAddr()
541 LIMITED_METHOD_CONTRACT;
545 void SetReturnAddress(TADDR val)
548 TADDR ptr = GetReturnAddressPtr();
549 _ASSERTE(ptr != NULL);
553 #ifndef DACCESS_COMPILE
554 void SetReturnContext(Context *pReturnContext)
557 PTR_Context* ppReturnContext = GetReturnContextAddr();
558 _ASSERTE(ppReturnContext);
559 *ppReturnContext = pReturnContext;
563 void SetReturnExecutionContext(OBJECTREF ref)
566 Object **pRef = GetReturnExecutionContextAddr();
568 *pRef = OBJECTREFToObject(ref);
571 OBJECTREF GetReturnExecutionContext()
574 Object **pRef = GetReturnExecutionContextAddr();
578 return ObjectToOBJECTREF(*pRef);
580 #endif // #ifndef DACCESS_COMPILE
582 PTR_GSCookie GetGSCookiePtr()
585 return dac_cast<PTR_GSCookie>(dac_cast<TADDR>(this) + GetOffsetOfGSCookie());
588 static int GetOffsetOfGSCookie()
590 LIMITED_METHOD_DAC_CONTRACT;
591 return -(int)sizeof(GSCookie);
594 static bool HasValidVTablePtr(Frame * pFrame);
595 static PTR_GSCookie SafeGetGSCookiePtr(Frame * pFrame);
599 // Callers, note that the REGDISPLAY parameter is actually in/out. While
600 // UpdateRegDisplay is generally used to fill out the REGDISPLAY parameter, some
601 // overrides (e.g., code:ResumableFrame::UpdateRegDisplay) will actually READ what
602 // you pass in. So be sure to pass in a valid or zeroed out REGDISPLAY.
603 virtual void UpdateRegDisplay(const PREGDISPLAY)
605 LIMITED_METHOD_DAC_CONTRACT;
609 //------------------------------------------------------------------------
611 //------------------------------------------------------------------------
618 TT_M2U, // we can safely cast to a FramedMethodFrame
619 TT_U2M, // we can safely cast to a UnmanagedToManagedFrame
620 TT_AppDomain, // transitioniting between AppDomains.
621 TT_InternalCall, // calling into the CLR (ecall/fcall).
624 // Get the type of transition.
626 virtual ETransitionType GetTransitionType()
628 LIMITED_METHOD_DAC_CONTRACT;
644 // HMFs and derived classes should use this so the profiling API knows it needs
645 // to ensure HMF-specific lazy initialization gets done w/out re-entering to the host.
646 TYPE_HELPER_METHOD_FRAME,
651 virtual int GetFrameType()
653 LIMITED_METHOD_DAC_CONTRACT;
654 return TYPE_INTERNAL;
657 // When stepping into a method, various other methods may be called.
658 // These are refererred to as interceptors. They are all invoked
659 // with frames of various types. GetInterception() indicates whether
660 // the frame was set up for execution of such interceptors
665 INTERCEPTION_CLASS_INIT,
666 INTERCEPTION_EXCEPTION,
667 INTERCEPTION_CONTEXT,
668 INTERCEPTION_SECURITY,
669 INTERCEPTION_PRESTUB,
675 virtual Interception GetInterception()
677 LIMITED_METHOD_DAC_CONTRACT;
678 return INTERCEPTION_NONE;
681 // Return information about an unmanaged call the frame
683 // ip - the unmanaged routine which will be called
684 // returnIP - the address in the stub which the unmanaged routine
686 // returnSP - the location returnIP is pushed onto the stack
689 virtual void GetUnmanagedCallSite(TADDR* ip,
693 LIMITED_METHOD_CONTRACT;
704 // Return where the frame will execute next - the result is filled
705 // into the given "trace" structure. The frame is responsible for
706 // detecting where it is in its execution lifetime.
707 virtual BOOL TraceFrame(Thread *thread, BOOL fromPatch,
708 TraceDestination *trace, REGDISPLAY *regs)
710 LIMITED_METHOD_CONTRACT;
711 LOG((LF_CORDB, LL_INFO10000,
712 "Default TraceFrame always returns false.\n"));
716 #ifdef DACCESS_COMPILE
717 virtual void EnumMemoryRegions(CLRDataEnumMemoryFlags flags)
722 // Many frames store a MethodDesc pointer in m_Datum
723 // so pick that up automatically.
724 MethodDesc* func = GetFunction();
727 func->EnumMemoryRegions(flags);
730 // Include the NegSpace
731 GSCookie * pGSCookie = GetGSCookiePtr();
732 _ASSERTE(FitsIn<ULONG32>(PBYTE(pGSCookie) - PBYTE(this)));
733 ULONG32 negSpaceSize = static_cast<ULONG32>(PBYTE(pGSCookie) - PBYTE(this));
734 DacEnumMemoryRegion(dac_cast<TADDR>(this) - negSpaceSize, negSpaceSize);
738 //---------------------------------------------------------------
739 // Expose key offsets and values for stub generation.
740 //---------------------------------------------------------------
741 static BYTE GetOffsetOfNextLink()
744 size_t ofs = offsetof(class Frame, m_Next);
745 _ASSERTE(FitsInI1(ofs));
749 // get your VTablePointer (can be used to check what type the frame is)
752 LIMITED_METHOD_DAC_CONTRACT;
753 return VPTR_HOST_VTABLE_TO_TADDR(*(LPVOID*)this);
756 #if defined(_DEBUG) && !defined(DACCESS_COMPILE)
757 virtual BOOL Protects(OBJECTREF *ppObjectRef)
759 LIMITED_METHOD_CONTRACT;
764 #ifndef DACCESS_COMPILE
765 // Link and Unlink this frame
768 VOID Push(Thread *pThread);
769 VOID Pop(Thread *pThread);
770 #endif // DACCESS_COMPILE
774 static BOOL ShouldLogTransitions() { WRAPPER_NO_CONTRACT; return LoggingOn(LF_STUBS, LL_INFO1000000); }
775 static void __stdcall LogTransition(Frame* frame);
776 void LogFrame(int LF, int LL); // General purpose logging.
777 void LogFrameChain(int LF, int LL); // Log the whole chain.
778 virtual const char* GetFrameTypeName() {return NULL;}
779 static PTR_CSTR GetFrameTypeName(TADDR vtbl);
782 //------------------------------------------------------------------------
783 // Returns the address of a security object or
784 // null if there is no space for an object on this frame.
785 //------------------------------------------------------------------------
786 virtual OBJECTREF *GetAddrOfSecurityDesc()
788 LIMITED_METHOD_CONTRACT;
793 // Pointer to the next frame up the stack.
796 PTR_Frame m_Next; // offset +4
799 PTR_Frame PtrNextFrame() { return m_Next; }
802 // Because JIT-method activations cannot be expressed as Frames,
803 // everyone must use the StackCrawler to walk the frame chain
804 // reliably. We'll expose the Next method only to the StackCrawler
805 // to prevent mistakes.
806 /*<TODO>@NICE: Restrict "friendship" again to the StackWalker method;
807 not done because of circular dependency with threads.h</TODO>
809 // friend Frame* Thread::StackWalkFrames(PSTACKWALKFRAMESCALLBACK pCallback, VOID *pData);
811 friend void CrawlFrame::GotoNextFrame();
812 friend class StackFrameIterator;
813 friend class TailCallFrame;
814 friend class AppDomain;
815 friend VOID RealCOMPlusThrow(OBJECTREF
816 #ifdef FEATURE_CORRUPTING_EXCEPTIONS
817 , CorruptionSeverity severity
818 #endif // FEATURE_CORRUPTING_EXCEPTIONS
820 friend FCDECL0(VOID, JIT_StressGC);
822 friend LONG WINAPI CLRVectoredExceptionHandlerShim(PEXCEPTION_POINTERS pExceptionInfo);
825 friend Thread * __stdcall JIT_InitPInvokeFrame(InlinedCallFrame *pFrame, PTR_VOID StubSecretArg);
827 #ifdef WIN64EXCEPTIONS
828 friend class ExceptionTracker;
830 #if defined(DACCESS_COMPILE)
831 friend class DacDbiInterfaceImpl;
832 #endif // DACCESS_COMPILE
833 #ifdef FEATURE_COMINTEROP
834 friend void COMToCLRWorkerBodyWithADTransition(Thread *pThread, ComMethodFrame *pFrame, ComCallWrapper *pWrap, UINT64 *pRetValOut);
835 #endif // FEATURE_COMINTEROP
839 LIMITED_METHOD_DAC_CONTRACT;
844 // Frame is considered an abstract class: this protected constructor
845 // causes any attempt to instantiate one to fail at compile-time.
847 : m_Next(dac_cast<PTR_Frame>(nullptr))
849 LIMITED_METHOD_CONTRACT;
852 #if defined(FEATURE_PAL) && !defined(DACCESS_COMPILE) && !defined(CROSSGEN_COMPILE)
853 virtual ~Frame() { LIMITED_METHOD_CONTRACT; }
856 #endif // FEATURE_PAL && !DACCESS_COMPILE && !CROSSGEN_COMPILE
860 //-----------------------------------------------------------------------------
861 // This frame provides context for a frame that
862 // took an exception that is going to be resumed.
864 // It is necessary to create this frame if garbage
865 // collection may happen during handling of the
866 // exception. The FRAME_ATTR_RESUMABLE flag tells
867 // the GC that the preceding frame needs to be treated
868 // like the top of stack (with the important implication that
869 // caller-save-regsiters will be potential roots).
870 //-----------------------------------------------------------------------------
871 #ifdef FEATURE_HIJACK
872 //-----------------------------------------------------------------------------
874 class ResumableFrame : public Frame
876 VPTR_VTABLE_CLASS(ResumableFrame, Frame)
879 #ifndef DACCESS_COMPILE
880 ResumableFrame(T_CONTEXT* regs) {
881 LIMITED_METHOD_CONTRACT;
886 virtual TADDR GetReturnAddressPtr();
888 virtual BOOL NeedsUpdateRegDisplay()
893 virtual void UpdateRegDisplay(const PREGDISPLAY pRD);
895 virtual unsigned GetFrameAttribs() {
896 LIMITED_METHOD_DAC_CONTRACT;
897 return FRAME_ATTR_RESUMABLE; // Treat the next frame as the top frame.
900 T_CONTEXT *GetContext() {
901 LIMITED_METHOD_DAC_CONTRACT;
905 #ifdef DACCESS_COMPILE
906 virtual void EnumMemoryRegions(CLRDataEnumMemoryFlags flags)
909 Frame::EnumMemoryRegions(flags);
917 // Keep as last entry in class
918 DEFINE_VTABLE_GETTER_AND_CTOR_AND_DTOR(ResumableFrame)
922 //-----------------------------------------------------------------------------
923 // RedirectedThreadFrame
924 //-----------------------------------------------------------------------------
926 class RedirectedThreadFrame : public ResumableFrame
928 VPTR_VTABLE_CLASS(RedirectedThreadFrame, ResumableFrame)
929 VPTR_UNIQUE(VPTR_UNIQUE_RedirectedThreadFrame)
932 #ifndef DACCESS_COMPILE
933 RedirectedThreadFrame(T_CONTEXT *regs) : ResumableFrame(regs) {
934 LIMITED_METHOD_CONTRACT;
937 virtual void ExceptionUnwind();
940 // Keep as last entry in class
941 DEFINE_VTABLE_GETTER_AND_CTOR_AND_DTOR(RedirectedThreadFrame)
944 typedef DPTR(RedirectedThreadFrame) PTR_RedirectedThreadFrame;
946 inline BOOL ISREDIRECTEDTHREAD(Thread * thread)
949 return (thread->GetFrame() != FRAME_TOP &&
950 thread->GetFrame()->GetVTablePtr() ==
951 RedirectedThreadFrame::GetMethodFrameVPtr());
954 inline T_CONTEXT * GETREDIRECTEDCONTEXT(Thread * thread)
957 _ASSERTE(ISREDIRECTEDTHREAD(thread));
958 return dac_cast<PTR_RedirectedThreadFrame>(thread->GetFrame())->GetContext();
961 //------------------------------------------------------------------------
962 #else // FEATURE_HIJACK
963 //------------------------------------------------------------------------
965 inline BOOL ISREDIRECTEDTHREAD(Thread * thread) { LIMITED_METHOD_CONTRACT; return FALSE; }
966 inline CONTEXT * GETREDIRECTEDCONTEXT(Thread * thread) { LIMITED_METHOD_CONTRACT; return (CONTEXT*) NULL; }
968 //------------------------------------------------------------------------
969 #endif // FEATURE_HIJACK
970 //------------------------------------------------------------------------
971 // This frame represents a transition from one or more nested frameless
972 // method calls to either a EE runtime helper function or a framed method.
973 // Because most stackwalks from the EE start with a full-fledged frame,
974 // anything but the most trivial call into the EE has to push this
975 // frame in order to prevent the frameless methods inbetween from
977 //------------------------------------------------------------------------
979 class TransitionFrame : public Frame
981 VPTR_ABSTRACT_VTABLE_CLASS(TransitionFrame, Frame)
984 virtual TADDR GetTransitionBlock() = 0;
986 // DACCESS: GetReturnAddressPtr should return the
987 // target address of the return address in the frame.
988 virtual TADDR GetReturnAddressPtr()
990 LIMITED_METHOD_DAC_CONTRACT;
991 return GetTransitionBlock() + TransitionBlock::GetOffsetOfReturnAddress();
994 //---------------------------------------------------------------
995 // Get the "this" object.
996 //---------------------------------------------------------------
1000 Object* obj = PTR_Object(*PTR_TADDR(GetAddrOfThis()));
1001 return ObjectToOBJECTREF(obj);
1004 PTR_OBJECTREF GetThisPtr()
1006 WRAPPER_NO_CONTRACT;
1007 return PTR_OBJECTREF(GetAddrOfThis());
1010 //---------------------------------------------------------------
1011 // Get the extra info for shared generic code.
1012 //---------------------------------------------------------------
1013 PTR_VOID GetParamTypeArg();
1015 protected: // we don't want people using this directly
1016 //---------------------------------------------------------------
1017 // Get the address of the "this" object. WARNING!!! Whether or not "this"
1018 // is gc-protected is depends on the frame type!!!
1019 //---------------------------------------------------------------
1020 TADDR GetAddrOfThis();
1023 //---------------------------------------------------------------
1024 // For vararg calls, return cookie.
1025 //---------------------------------------------------------------
1026 VASigCookie *GetVASigCookie();
1028 CalleeSavedRegisters *GetCalleeSavedRegisters()
1030 LIMITED_METHOD_DAC_CONTRACT;
1031 return dac_cast<PTR_CalleeSavedRegisters>(
1032 GetTransitionBlock() + TransitionBlock::GetOffsetOfCalleeSavedRegisters());
1035 ArgumentRegisters *GetArgumentRegisters()
1037 LIMITED_METHOD_DAC_CONTRACT;
1038 return dac_cast<PTR_ArgumentRegisters>(
1039 GetTransitionBlock() + TransitionBlock::GetOffsetOfArgumentRegisters());
1044 LIMITED_METHOD_DAC_CONTRACT;
1045 return GetTransitionBlock() + sizeof(TransitionBlock);
1048 virtual BOOL NeedsUpdateRegDisplay()
1053 virtual void UpdateRegDisplay(const PREGDISPLAY);
1055 void UpdateRegDisplayHelper(const PREGDISPLAY, UINT cbStackPop);
1058 #if defined (_DEBUG) && !defined (DACCESS_COMPILE)
1059 virtual BOOL Protects(OBJECTREF *ppORef);
1060 #endif //defined (_DEBUG) && defined (DACCESS_COMPILE)
1062 // For use by classes deriving from FramedMethodFrame.
1063 void PromoteCallerStack(promote_func* fn, ScanContext* sc);
1065 void PromoteCallerStackHelper(promote_func* fn, ScanContext* sc,
1066 MethodDesc * pMD, MetaSig *pmsig);
1068 void PromoteCallerStackUsingGCRefMap(promote_func* fn, ScanContext* sc, PTR_BYTE pGCRefMap);
1071 UINT CbStackPopUsingGCRefMap(PTR_BYTE pGCRefMap);
1077 LIMITED_METHOD_CONTRACT;
1081 //-----------------------------------------------------------------------
1082 // TransitionFrames for exceptions
1083 //-----------------------------------------------------------------------
1085 // The define USE_FEF controls how this class is used. Look for occurances
1088 class FaultingExceptionFrame : public Frame
1090 friend class CheckAsmOffsets;
1092 #ifndef WIN64EXCEPTIONS
1095 CalleeSavedRegisters m_regs;
1096 TADDR m_ReturnAddress;
1097 #else // _TARGET_X86_
1098 #error "Unsupported architecture"
1099 #endif // _TARGET_X86_
1100 #else // WIN64EXCEPTIONS
1101 BOOL m_fFilterExecuted; // Flag for FirstCallToHandler
1102 TADDR m_ReturnAddress;
1104 #endif // !WIN64EXCEPTIONS
1106 VPTR_VTABLE_CLASS(FaultingExceptionFrame, Frame)
1109 #ifndef DACCESS_COMPILE
1110 FaultingExceptionFrame() {
1111 LIMITED_METHOD_CONTRACT;
1115 virtual TADDR GetReturnAddressPtr()
1117 LIMITED_METHOD_DAC_CONTRACT;
1118 return PTR_HOST_MEMBER_TADDR(FaultingExceptionFrame, this, m_ReturnAddress);
1121 void Init(T_CONTEXT *pContext);
1122 void InitAndLink(T_CONTEXT *pContext);
1124 Interception GetInterception()
1126 LIMITED_METHOD_DAC_CONTRACT;
1127 return INTERCEPTION_EXCEPTION;
1130 unsigned GetFrameAttribs()
1132 LIMITED_METHOD_DAC_CONTRACT;
1133 return FRAME_ATTR_EXCEPTION | FRAME_ATTR_FAULTED;
1136 #ifndef WIN64EXCEPTIONS
1137 CalleeSavedRegisters *GetCalleeSavedRegisters()
1140 LIMITED_METHOD_DAC_CONTRACT;
1143 PORTABILITY_ASSERT("GetCalleeSavedRegisters");
1144 #endif // _TARGET_X86_
1146 #endif // WIN64EXCEPTIONS
1148 #ifdef WIN64EXCEPTIONS
1149 T_CONTEXT *GetExceptionContext ()
1151 LIMITED_METHOD_CONTRACT;
1155 BOOL * GetFilterExecutedFlag()
1157 LIMITED_METHOD_CONTRACT;
1158 return &m_fFilterExecuted;
1160 #endif // WIN64EXCEPTIONS
1162 virtual BOOL NeedsUpdateRegDisplay()
1167 virtual void UpdateRegDisplay(const PREGDISPLAY);
1169 // Keep as last entry in class
1170 DEFINE_VTABLE_GETTER_AND_DTOR(FaultingExceptionFrame)
1173 //-----------------------------------------------------------------------
1174 // Frame for debugger function evaluation
1176 // This frame holds a ptr to a DebuggerEval object which contains a copy
1177 // of the thread's context at the time it was hijacked for the func
1180 // UpdateRegDisplay updates all registers inthe REGDISPLAY, not just
1181 // the callee saved registers, because we can hijack for a func eval
1182 // at any point in a thread's execution.
1184 //-----------------------------------------------------------------------
1186 #ifdef DEBUGGING_SUPPORTED
1188 typedef DPTR(class DebuggerEval) PTR_DebuggerEval;
1190 class FuncEvalFrame : public Frame
1192 VPTR_VTABLE_CLASS(FuncEvalFrame, Frame)
1194 TADDR m_ReturnAddress;
1195 PTR_DebuggerEval m_pDebuggerEval;
1200 #ifndef DACCESS_COMPILE
1201 FuncEvalFrame(DebuggerEval *pDebuggerEval, TADDR returnAddress, BOOL showFrame)
1203 LIMITED_METHOD_CONTRACT;
1204 m_pDebuggerEval = pDebuggerEval;
1205 m_ReturnAddress = returnAddress;
1206 m_showFrame = showFrame;
1210 virtual BOOL IsTransitionToNativeFrame()
1212 LIMITED_METHOD_CONTRACT;
1216 virtual int GetFrameType()
1218 LIMITED_METHOD_DAC_CONTRACT;
1219 return TYPE_FUNC_EVAL;
1222 virtual unsigned GetFrameAttribs();
1224 virtual BOOL NeedsUpdateRegDisplay()
1229 virtual void UpdateRegDisplay(const PREGDISPLAY);
1231 virtual DebuggerEval * GetDebuggerEval();
1233 virtual TADDR GetReturnAddressPtr();
1238 * Returns if this frame should be returned as part of a stack trace to a debugger or not.
1243 LIMITED_METHOD_CONTRACT;
1248 // Keep as last entry in class
1249 DEFINE_VTABLE_GETTER_AND_CTOR_AND_DTOR(FuncEvalFrame)
1252 typedef VPTR(FuncEvalFrame) PTR_FuncEvalFrame;
1253 #endif // DEBUGGING_SUPPORTED
1255 //----------------------------------------------------------------------------------------------
1256 // A HelperMethodFrame is created by jit helper (Modified slightly it could be used
1257 // for native routines). This frame just does the callee saved register fixup.
1258 // It does NOT protect arguments; you must use GCPROTECT or one of the HelperMethodFrame
1259 // subclases. (see JitInterface for sample use, YOU CAN'T RETURN WHILE IN THE PROTECTED STATE!)
1260 //----------------------------------------------------------------------------------------------
1262 class HelperMethodFrame : public Frame
1264 VPTR_VTABLE_CLASS(HelperMethodFrame, Frame);
1267 #ifndef DACCESS_COMPILE
1268 // Lazy initialization of HelperMethodFrame. Need to
1269 // call InsureInit to complete initialization
1270 // If this is an FCall, the first param is the entry point for the FCALL.
1271 // The MethodDesc will be looked up form this (lazily), and this method
1272 // will be used in stack reporting, if this is not an FCall pass a 0
1273 FORCEINLINE HelperMethodFrame(void* fCallFtnEntry, unsigned attribs = 0)
1275 WRAPPER_NO_CONTRACT;
1276 // Most of the initialization is actually done in HelperMethodFrame::Push()
1277 INDEBUG(memset(&m_Attribs, 0xCC, sizeof(HelperMethodFrame) - offsetof(HelperMethodFrame, m_Attribs));)
1278 m_Attribs = attribs;
1279 m_FCallEntry = (TADDR)fCallFtnEntry;
1281 #endif // DACCESS_COMPILE
1283 virtual int GetFrameType()
1285 LIMITED_METHOD_DAC_CONTRACT;
1286 return TYPE_HELPER_METHOD_FRAME;
1289 virtual PCODE GetReturnAddress()
1291 LIMITED_METHOD_DAC_CONTRACT;
1293 if (!m_MachState.isValid())
1295 #if defined(DACCESS_COMPILE)
1296 MachState unwoundState;
1297 InsureInit(false, &unwoundState);
1298 return unwoundState.GetRetAddr();
1299 #else // !DACCESS_COMPILE
1300 _ASSERTE(!"HMF's should always be initialized in the non-DAC world.");
1303 #endif // !DACCESS_COMPILE
1306 return m_MachState.GetRetAddr();
1309 virtual MethodDesc* GetFunction();
1311 virtual BOOL NeedsUpdateRegDisplay()
1316 virtual void UpdateRegDisplay(const PREGDISPLAY);
1318 virtual Interception GetInterception()
1320 WRAPPER_NO_CONTRACT;
1321 LIMITED_METHOD_DAC_CONTRACT;
1322 if (GetFrameAttribs() & FRAME_ATTR_EXCEPTION)
1323 return(INTERCEPTION_EXCEPTION);
1324 return(INTERCEPTION_NONE);
1327 virtual ETransitionType GetTransitionType()
1329 LIMITED_METHOD_DAC_CONTRACT;
1330 return TT_InternalCall;
1334 void SetAddrOfHaveCheckedRestoreState(BOOL* pDoneCheck)
1336 m_pDoneCheck = pDoneCheck;
1339 BOOL HaveDoneConfirmStateCheck()
1341 LIMITED_METHOD_CONTRACT;
1342 _ASSERTE(m_pDoneCheck != NULL);
1343 return *m_pDoneCheck;
1346 void SetHaveDoneConfirmStateCheck()
1348 LIMITED_METHOD_CONTRACT;
1349 _ASSERTE(m_pDoneCheck != NULL);
1350 *m_pDoneCheck = TRUE;
1354 virtual unsigned GetFrameAttribs()
1356 LIMITED_METHOD_DAC_CONTRACT;
1360 #ifdef DACCESS_COMPILE
1361 virtual void EnumMemoryRegions(CLRDataEnumMemoryFlags flags)
1363 WRAPPER_NO_CONTRACT;
1364 Frame::EnumMemoryRegions(flags);
1368 #ifndef DACCESS_COMPILE
1372 FORCEINLINE void Poll()
1374 WRAPPER_NO_CONTRACT;
1375 if (m_pThread->CatchAtSafePointOpportunistic())
1378 #endif // DACCESS_COMPILE
1380 BOOL InsureInit(bool initialInit, struct MachState* unwindState, HostCallPreference hostCallPreference = AllowHostCalls);
1382 LazyMachState * MachineState() {
1383 LIMITED_METHOD_CONTRACT;
1384 return &m_MachState;
1387 Thread * GetThread() {
1388 LIMITED_METHOD_CONTRACT;
1393 // Slow paths of Push/Pop are factored into a separate functions for better perf.
1394 NOINLINE void PushSlowHelper();
1395 NOINLINE void PopSlowHelper();
1398 PTR_MethodDesc m_pMD;
1400 INDEBUG(BOOL* m_pDoneCheck;)
1401 PTR_Thread m_pThread;
1402 TADDR m_FCallEntry; // used to determine our identity for stack traces
1404 LazyMachState m_MachState; // pRetAddr points to the return address and the stack arguments
1406 // Keep as last entry in class
1407 DEFINE_VTABLE_GETTER_AND_CTOR_AND_DTOR(HelperMethodFrame)
1410 // Restores registers saved in m_MachState
1411 EXTERN_C int __fastcall HelperMethodFrameRestoreState(
1412 INDEBUG_COMMA(HelperMethodFrame *pFrame)
1417 // workhorse for our promotion efforts
1418 inline void DoPromote(promote_func *fn, ScanContext* sc, OBJECTREF *address, BOOL interior)
1420 WRAPPER_NO_CONTRACT;
1422 // We use OBJECTREF_TO_UNCHECKED_OBJECTREF since address may be an interior pointer
1424 " Promoting pointer argument at" FMT_ADDR "from" FMT_ADDR "to ",
1425 DBG_ADDR(address), DBG_ADDR(OBJECTREF_TO_UNCHECKED_OBJECTREF(*address)) ));
1428 PromoteCarefully(fn, PTR_PTR_Object(address), sc);
1430 (*fn) (PTR_PTR_Object(address), sc, 0);
1432 LOG((LF_GC, INFO3, " " FMT_ADDR "\n", DBG_ADDR(OBJECTREF_TO_UNCHECKED_OBJECTREF(*address)) ));
1436 //-----------------------------------------------------------------------------
1437 // a HelplerMethodFrames that also report additional object references
1438 //-----------------------------------------------------------------------------
1440 class HelperMethodFrame_1OBJ : public HelperMethodFrame
1442 VPTR_VTABLE_CLASS(HelperMethodFrame_1OBJ, HelperMethodFrame)
1445 #if !defined(DACCESS_COMPILE) && !defined(CROSSGEN_COMPILE)
1446 HelperMethodFrame_1OBJ(void* fCallFtnEntry, unsigned attribs, OBJECTREF* aGCPtr1)
1447 : HelperMethodFrame(fCallFtnEntry, attribs)
1449 LIMITED_METHOD_CONTRACT;
1450 gcPtrs[0] = aGCPtr1;
1451 INDEBUG(Thread::ObjectRefProtected(aGCPtr1);)
1452 INDEBUG((*aGCPtr1).Validate ();)
1456 void SetProtectedObject(PTR_OBJECTREF objPtr)
1458 LIMITED_METHOD_CONTRACT;
1460 INDEBUG(Thread::ObjectRefProtected(objPtr);)
1463 virtual void GcScanRoots(promote_func *fn, ScanContext* sc)
1465 WRAPPER_NO_CONTRACT;
1466 DoPromote(fn, sc, gcPtrs[0], FALSE);
1467 HelperMethodFrame::GcScanRoots(fn, sc);
1471 #ifndef DACCESS_COMPILE
1474 WRAPPER_NO_CONTRACT;
1475 HelperMethodFrame::Pop();
1476 Thread::ObjectRefNew(gcPtrs[0]);
1478 #endif // DACCESS_COMPILE
1480 BOOL Protects(OBJECTREF *ppORef)
1482 LIMITED_METHOD_CONTRACT;
1483 return (ppORef == gcPtrs[0]) ? TRUE : FALSE;
1489 PTR_OBJECTREF gcPtrs[1];
1491 // Keep as last entry in class
1492 DEFINE_VTABLE_GETTER_AND_CTOR_AND_DTOR(HelperMethodFrame_1OBJ)
1496 //-----------------------------------------------------------------------------
1497 // HelperMethodFrame_2OBJ
1498 //-----------------------------------------------------------------------------
1500 class HelperMethodFrame_2OBJ : public HelperMethodFrame
1502 VPTR_VTABLE_CLASS(HelperMethodFrame_2OBJ, HelperMethodFrame)
1505 #if !defined(DACCESS_COMPILE) && !defined(CROSSGEN_COMPILE)
1506 HelperMethodFrame_2OBJ(
1507 void* fCallFtnEntry,
1511 : HelperMethodFrame(fCallFtnEntry, attribs)
1513 LIMITED_METHOD_CONTRACT;
1514 gcPtrs[0] = aGCPtr1;
1515 gcPtrs[1] = aGCPtr2;
1516 INDEBUG(Thread::ObjectRefProtected(aGCPtr1);)
1517 INDEBUG(Thread::ObjectRefProtected(aGCPtr2);)
1518 INDEBUG((*aGCPtr1).Validate ();)
1519 INDEBUG((*aGCPtr2).Validate ();)
1523 virtual void GcScanRoots(promote_func *fn, ScanContext* sc)
1525 WRAPPER_NO_CONTRACT;
1526 DoPromote(fn, sc, gcPtrs[0], FALSE);
1527 DoPromote(fn, sc, gcPtrs[1], FALSE);
1528 HelperMethodFrame::GcScanRoots(fn, sc);
1532 #ifndef DACCESS_COMPILE
1535 WRAPPER_NO_CONTRACT;
1536 HelperMethodFrame::Pop();
1537 Thread::ObjectRefNew(gcPtrs[0]);
1538 Thread::ObjectRefNew(gcPtrs[1]);
1540 #endif // DACCESS_COMPILE
1542 BOOL Protects(OBJECTREF *ppORef)
1544 LIMITED_METHOD_CONTRACT;
1545 return (ppORef == gcPtrs[0] || ppORef == gcPtrs[1]) ? TRUE : FALSE;
1550 PTR_OBJECTREF gcPtrs[2];
1552 // Keep as last entry in class
1553 DEFINE_VTABLE_GETTER_AND_CTOR_AND_DTOR(HelperMethodFrame_2OBJ)
1557 //-----------------------------------------------------------------------------
1558 // HelperMethodFrame_PROTECTOBJ
1559 //-----------------------------------------------------------------------------
1561 class HelperMethodFrame_PROTECTOBJ : public HelperMethodFrame
1563 VPTR_VTABLE_CLASS(HelperMethodFrame_PROTECTOBJ, HelperMethodFrame)
1566 #if !defined(DACCESS_COMPILE) && !defined(CROSSGEN_COMPILE)
1567 HelperMethodFrame_PROTECTOBJ(void* fCallFtnEntry, unsigned attribs, OBJECTREF* pObjRefs, int numObjRefs)
1568 : HelperMethodFrame(fCallFtnEntry, attribs)
1570 LIMITED_METHOD_CONTRACT;
1571 m_pObjRefs = pObjRefs;
1572 m_numObjRefs = numObjRefs;
1574 for (UINT i = 0; i < m_numObjRefs; i++) {
1575 Thread::ObjectRefProtected(&m_pObjRefs[i]);
1576 m_pObjRefs[i].Validate();
1582 virtual void GcScanRoots(promote_func *fn, ScanContext* sc)
1584 WRAPPER_NO_CONTRACT;
1585 for (UINT i = 0; i < m_numObjRefs; i++) {
1586 DoPromote(fn, sc, &m_pObjRefs[i], FALSE);
1588 HelperMethodFrame::GcScanRoots(fn, sc);
1592 #ifndef DACCESS_COMPILE
1595 WRAPPER_NO_CONTRACT;
1596 HelperMethodFrame::Pop();
1597 for (UINT i = 0; i < m_numObjRefs; i++) {
1598 Thread::ObjectRefNew(&m_pObjRefs[i]);
1601 #endif // DACCESS_COMPILE
1603 BOOL Protects(OBJECTREF *ppORef)
1605 LIMITED_METHOD_CONTRACT;
1606 for (UINT i = 0; i < m_numObjRefs; i++) {
1607 if (ppORef == &m_pObjRefs[i])
1615 PTR_OBJECTREF m_pObjRefs;
1618 // Keep as last entry in class
1619 DEFINE_VTABLE_GETTER_AND_CTOR_AND_DTOR(HelperMethodFrame_PROTECTOBJ)
1622 class FramedMethodFrame : public TransitionFrame
1624 VPTR_ABSTRACT_VTABLE_CLASS(FramedMethodFrame, TransitionFrame)
1626 TADDR m_pTransitionBlock;
1629 PTR_MethodDesc m_pMD;
1632 #ifndef DACCESS_COMPILE
1633 FramedMethodFrame(TransitionBlock * pTransitionBlock, MethodDesc * pMD)
1634 : m_pTransitionBlock(dac_cast<TADDR>(pTransitionBlock)), m_pMD(pMD)
1636 LIMITED_METHOD_CONTRACT;
1638 #endif // DACCESS_COMPILE
1640 virtual TADDR GetTransitionBlock()
1642 LIMITED_METHOD_DAC_CONTRACT;
1643 return m_pTransitionBlock;
1646 virtual MethodDesc *GetFunction()
1648 LIMITED_METHOD_DAC_CONTRACT;
1652 #ifndef DACCESS_COMPILE
1653 void SetFunction(MethodDesc *pMD)
1659 MODE_COOPERATIVE; // Frame MethodDesc should be always updated in cooperative mode to avoid racing with GC stackwalk
1668 virtual ETransitionType GetTransitionType()
1670 LIMITED_METHOD_DAC_CONTRACT;
1671 return TT_M2U; // we can safely cast to a FramedMethodFrame
1676 LIMITED_METHOD_DAC_CONTRACT;
1680 #ifdef COM_STUBS_SEPARATE_FP_LOCATIONS
1681 static int GetFPArgOffset(int iArg)
1683 #ifdef _TARGET_AMD64_
1684 // Floating point spill area is between return value and transition block for frames that need it
1685 // (code:TPMethodFrame and code:ComPlusMethodFrame)
1686 return -(4 * 0x10 /* floating point args */ + 0x8 /* alignment pad */ + TransitionBlock::GetNegSpaceSize()) + (iArg * 0x10);
1692 // GetReturnObjectPtr and GetReturnValuePtr are only valid on frames
1695 PTR_PTR_Object GetReturnObjectPtr()
1697 LIMITED_METHOD_DAC_CONTRACT;
1698 return PTR_PTR_Object(GetReturnValuePtr());
1701 // Get return value address
1702 PTR_VOID GetReturnValuePtr()
1704 LIMITED_METHOD_DAC_CONTRACT;
1705 #ifdef COM_STUBS_SEPARATE_FP_LOCATIONS
1706 TADDR p = GetTransitionBlock() + GetFPArgOffset(0);
1708 TADDR p = GetTransitionBlock() - TransitionBlock::GetNegSpaceSize();
1710 // Return value is right before the transition block (or floating point spill area on AMD64) for frames that need it
1711 // (code:TPMethodFrame and code:ComPlusMethodFrame)
1712 #ifdef ENREGISTERED_RETURNTYPE_MAXSIZE
1713 p -= ENREGISTERED_RETURNTYPE_MAXSIZE;
1715 p -= sizeof(ARG_SLOT);
1717 return dac_cast<PTR_VOID>(p);
1723 LIMITED_METHOD_CONTRACT;
1727 //+----------------------------------------------------------------------------
1729 // Class: TPMethodFrame private
1731 // Synopsis: This frame is pushed onto the stack for calls on transparent
1735 //+----------------------------------------------------------------------------
1737 //------------------------------------------------------------------------
1738 // This represents a call Delegate.Invoke for secure delegate
1739 // It's only used to gc-protect the arguments during the call.
1740 // Actually the only reason to have this frame is so a proper
1741 // Assembly can be reported
1742 //------------------------------------------------------------------------
1744 class SecureDelegateFrame : public TransitionFrame
1746 VPTR_VTABLE_CLASS(SecureDelegateFrame, TransitionFrame)
1748 PTR_MethodDesc m_pMD;
1749 TransitionBlock m_TransitionBlock;
1752 virtual MethodDesc* GetFunction()
1754 LIMITED_METHOD_CONTRACT;
1758 virtual TADDR GetTransitionBlock()
1760 LIMITED_METHOD_DAC_CONTRACT;
1761 return PTR_HOST_MEMBER_TADDR(SecureDelegateFrame, this,
1765 static BYTE GetOffsetOfDatum()
1767 LIMITED_METHOD_DAC_CONTRACT;
1768 return offsetof(SecureDelegateFrame, m_pMD);
1771 static int GetOffsetOfTransitionBlock()
1773 LIMITED_METHOD_DAC_CONTRACT;
1774 return offsetof(SecureDelegateFrame, m_TransitionBlock);
1777 virtual void GcScanRoots(promote_func *fn, ScanContext* sc)
1779 WRAPPER_NO_CONTRACT;
1780 TransitionFrame::GcScanRoots(fn, sc);
1781 PromoteCallerStack(fn, sc);
1784 virtual Assembly *GetAssembly();
1788 LIMITED_METHOD_DAC_CONTRACT;
1789 return TYPE_MULTICAST;
1792 // For the debugger:
1793 // Our base class, FramedMethodFrame, is a M2U transition;
1794 // but Delegate.Invoke isn't. So override and fix it here.
1795 // If we didn't do this, we'd see a Managed/Unmanaged transition in debugger's stack trace.
1796 virtual ETransitionType GetTransitionType()
1798 LIMITED_METHOD_DAC_CONTRACT;
1802 virtual BOOL TraceFrame(Thread *thread, BOOL fromPatch,
1803 TraceDestination *trace, REGDISPLAY *regs);
1805 // Keep as last entry in class
1806 DEFINE_VTABLE_GETTER_AND_CTOR_AND_DTOR(SecureDelegateFrame)
1810 //------------------------------------------------------------------------
1811 // This represents a call Multicast.Invoke. It's only used to gc-protect
1812 // the arguments during the iteration.
1813 //------------------------------------------------------------------------
1815 class MulticastFrame : public SecureDelegateFrame
1817 VPTR_VTABLE_CLASS(MulticastFrame, SecureDelegateFrame)
1821 virtual Assembly *GetAssembly()
1823 WRAPPER_NO_CONTRACT;
1824 return Frame::GetAssembly();
1829 LIMITED_METHOD_DAC_CONTRACT;
1830 return TYPE_MULTICAST;
1833 virtual BOOL TraceFrame(Thread *thread, BOOL fromPatch,
1834 TraceDestination *trace, REGDISPLAY *regs);
1836 // Keep as last entry in class
1837 DEFINE_VTABLE_GETTER_AND_CTOR_AND_DTOR(MulticastFrame)
1841 //-----------------------------------------------------------------------
1842 // Transition frame from unmanaged to managed
1843 //-----------------------------------------------------------------------
1845 class UnmanagedToManagedFrame : public Frame
1847 friend class CheckAsmOffsets;
1849 VPTR_ABSTRACT_VTABLE_CLASS_AND_CTOR(UnmanagedToManagedFrame, Frame)
1853 // DACCESS: GetReturnAddressPtr should return the
1854 // target address of the return address in the frame.
1855 virtual TADDR GetReturnAddressPtr()
1857 LIMITED_METHOD_DAC_CONTRACT;
1858 return PTR_HOST_MEMBER_TADDR(UnmanagedToManagedFrame, this,
1862 virtual PCODE GetReturnAddress();
1864 // Retrieves pointer to the lowest-addressed argument on
1865 // the stack. Depending on the calling convention, this
1866 // may or may not be the first argument.
1867 TADDR GetPointerToArguments()
1869 LIMITED_METHOD_DAC_CONTRACT;
1870 return dac_cast<TADDR>(this) + GetOffsetOfArgs();
1873 // Exposes an offset for stub generation.
1874 static BYTE GetOffsetOfArgs()
1876 LIMITED_METHOD_DAC_CONTRACT;
1877 #if defined(_TARGET_ARM_) || defined(_TARGET_ARM64_)
1878 size_t ofs = offsetof(UnmanagedToManagedFrame, m_argumentRegisters);
1880 size_t ofs = sizeof(UnmanagedToManagedFrame);
1882 _ASSERTE(FitsInI1(ofs));
1886 // depends on the sub frames to return approp. type here
1889 LIMITED_METHOD_DAC_CONTRACT;
1893 static int GetOffsetOfDatum()
1895 LIMITED_METHOD_CONTRACT;
1896 return offsetof(UnmanagedToManagedFrame, m_pvDatum);
1900 static int GetOffsetOfCalleeSavedRegisters()
1902 LIMITED_METHOD_CONTRACT;
1903 return offsetof(UnmanagedToManagedFrame, m_calleeSavedRegisters);
1909 LIMITED_METHOD_DAC_CONTRACT;
1913 //------------------------------------------------------------------------
1914 // For the debugger.
1915 //------------------------------------------------------------------------
1916 virtual ETransitionType GetTransitionType()
1918 LIMITED_METHOD_DAC_CONTRACT;
1922 //------------------------------------------------------------------------
1923 // Performs cleanup on an exception unwind
1924 //------------------------------------------------------------------------
1925 #ifndef DACCESS_COMPILE
1926 virtual void ExceptionUnwind();
1930 TADDR m_pvDatum; // type depends on the sub class
1932 #if defined(_TARGET_X86_)
1933 CalleeSavedRegisters m_calleeSavedRegisters;
1934 TADDR m_ReturnAddress;
1935 #elif defined(_TARGET_ARM_)
1936 TADDR m_R11; // R11 chain
1937 TADDR m_ReturnAddress;
1938 ArgumentRegisters m_argumentRegisters;
1939 #elif defined (_TARGET_ARM64_)
1941 TADDR m_ReturnAddress;
1942 ArgumentRegisters m_argumentRegisters;
1944 TADDR m_ReturnAddress; // return address into unmanaged code
1948 #ifdef FEATURE_COMINTEROP
1950 //------------------------------------------------------------------------
1951 // This frame represents a transition from COM to COM+
1952 //------------------------------------------------------------------------
1954 class ComMethodFrame : public UnmanagedToManagedFrame
1956 VPTR_VTABLE_CLASS(ComMethodFrame, UnmanagedToManagedFrame)
1957 VPTR_UNIQUE(VPTR_UNIQUE_ComMethodFrame)
1962 // Return the # of stack bytes pushed by the unmanaged caller.
1963 UINT GetNumCallerStackBytes();
1966 PTR_ComCallMethodDesc GetComCallMethodDesc()
1968 LIMITED_METHOD_CONTRACT;
1969 return dac_cast<PTR_ComCallMethodDesc>(m_pvDatum);
1972 #ifndef DACCESS_COMPILE
1973 static void DoSecondPassHandlerCleanup(Frame * pCurFrame);
1974 #endif // !DACCESS_COMPILE
1977 // Keep as last entry in class
1978 DEFINE_VTABLE_GETTER_AND_CTOR_AND_DTOR(ComMethodFrame)
1981 typedef DPTR(class ComMethodFrame) PTR_ComMethodFrame;
1983 //------------------------------------------------------------------------
1984 // This represents a generic call from CLR to COM
1985 //------------------------------------------------------------------------
1987 class ComPlusMethodFrame : public FramedMethodFrame
1989 VPTR_VTABLE_CLASS(ComPlusMethodFrame, FramedMethodFrame)
1992 ComPlusMethodFrame(TransitionBlock * pTransitionBlock, MethodDesc * pMethodDesc);
1994 virtual void GcScanRoots(promote_func *fn, ScanContext* sc);
1996 virtual BOOL IsTransitionToNativeFrame()
1998 LIMITED_METHOD_CONTRACT;
2004 LIMITED_METHOD_DAC_CONTRACT;
2008 void GetUnmanagedCallSite(TADDR* ip,
2012 BOOL TraceFrame(Thread *thread, BOOL fromPatch,
2013 TraceDestination *trace, REGDISPLAY *regs);
2015 // Keep as last entry in class
2016 DEFINE_VTABLE_GETTER_AND_CTOR_AND_DTOR(ComPlusMethodFrame)
2019 #endif // FEATURE_COMINTEROP
2021 //------------------------------------------------------------------------
2022 // This represents a call from a helper to GetILStubForCalli
2023 //------------------------------------------------------------------------
2025 class PInvokeCalliFrame : public FramedMethodFrame
2027 VPTR_VTABLE_CLASS(PInvokeCalliFrame, FramedMethodFrame)
2029 PTR_VASigCookie m_pVASigCookie;
2030 PCODE m_pUnmanagedTarget;
2033 PInvokeCalliFrame(TransitionBlock * pTransitionBlock, VASigCookie * pVASigCookie, PCODE pUnmanagedTarget);
2035 virtual void GcScanRoots(promote_func *fn, ScanContext* sc)
2037 WRAPPER_NO_CONTRACT;
2038 FramedMethodFrame::GcScanRoots(fn, sc);
2039 PromoteCallerStack(fn, sc);
2042 void PromoteCallerStack(promote_func* fn, ScanContext* sc);
2045 virtual MethodDesc *GetFunction()
2047 LIMITED_METHOD_DAC_CONTRACT;
2053 LIMITED_METHOD_DAC_CONTRACT;
2054 return TYPE_INTERCEPTION;
2057 PCODE GetPInvokeCalliTarget()
2059 LIMITED_METHOD_CONTRACT;
2060 return m_pUnmanagedTarget;
2063 PTR_VASigCookie GetVASigCookie()
2065 LIMITED_METHOD_CONTRACT;
2066 return m_pVASigCookie;
2070 virtual void UpdateRegDisplay(const PREGDISPLAY);
2071 #endif // _TARGET_X86_
2073 BOOL TraceFrame(Thread *thread, BOOL fromPatch,
2074 TraceDestination *trace, REGDISPLAY *regs)
2076 WRAPPER_NO_CONTRACT;
2078 trace->InitForUnmanaged(GetPInvokeCalliTarget());
2082 // Keep as last entry in class
2083 DEFINE_VTABLE_GETTER_AND_CTOR_AND_DTOR(PInvokeCalliFrame)
2086 // Some context-related forwards.
2087 #ifdef FEATURE_HIJACK
2088 //------------------------------------------------------------------------
2089 // This frame represents a hijacked return. If we crawl back through it,
2090 // it gets us back to where the return should have gone (and eventually will
2092 //------------------------------------------------------------------------
2093 class HijackFrame : public Frame
2095 VPTR_VTABLE_CLASS(HijackFrame, Frame)
2096 VPTR_UNIQUE(VPTR_UNIQUE_HijackFrame);
2099 // DACCESS: GetReturnAddressPtr should return the
2100 // target address of the return address in the frame.
2101 virtual TADDR GetReturnAddressPtr()
2103 LIMITED_METHOD_DAC_CONTRACT;
2104 return PTR_HOST_MEMBER_TADDR(HijackFrame, this,
2108 virtual BOOL NeedsUpdateRegDisplay()
2110 LIMITED_METHOD_CONTRACT;
2114 virtual void UpdateRegDisplay(const PREGDISPLAY);
2115 virtual void GcScanRoots(promote_func *fn, ScanContext* sc);
2117 // HijackFrames are created by trip functions. See OnHijackTripThread()
2118 // They are real C++ objects on the stack.
2119 // So, it's a public function -- but that doesn't mean you should make some.
2120 HijackFrame(LPVOID returnAddress, Thread *thread, HijackArgs *args);
2124 TADDR m_ReturnAddress;
2125 PTR_Thread m_Thread;
2126 DPTR(HijackArgs) m_Args;
2128 // Keep as last entry in class
2129 DEFINE_VTABLE_GETTER_AND_CTOR_AND_DTOR(HijackFrame)
2132 #endif // FEATURE_HIJACK
2134 //------------------------------------------------------------------------
2135 // This represents a call to a method prestub. Because the prestub
2136 // can do gc and throw exceptions while building the replacement
2137 // stub, we need this frame to keep things straight.
2138 //------------------------------------------------------------------------
2140 class PrestubMethodFrame : public FramedMethodFrame
2142 VPTR_VTABLE_CLASS(PrestubMethodFrame, FramedMethodFrame)
2145 PrestubMethodFrame(TransitionBlock * pTransitionBlock, MethodDesc * pMD);
2147 virtual void GcScanRoots(promote_func *fn, ScanContext* sc)
2149 WRAPPER_NO_CONTRACT;
2150 FramedMethodFrame::GcScanRoots(fn, sc);
2151 PromoteCallerStack(fn, sc);
2154 BOOL TraceFrame(Thread *thread, BOOL fromPatch,
2155 TraceDestination *trace, REGDISPLAY *regs);
2159 LIMITED_METHOD_DAC_CONTRACT;
2160 return TYPE_INTERCEPTION;
2163 // Our base class is a a M2U TransitionType; but we're not. So override and set us back to None.
2164 ETransitionType GetTransitionType()
2166 LIMITED_METHOD_DAC_CONTRACT;
2170 Interception GetInterception();
2172 // Keep as last entry in class
2173 DEFINE_VTABLE_GETTER_AND_CTOR_AND_DTOR(PrestubMethodFrame)
2176 //------------------------------------------------------------------------
2177 // This represents a call into the virtual call stub manager
2178 // Because the stub manager can do gc and throw exceptions while
2179 // building the resolve and dispatch stubs and needs to communicate
2180 // if we need to setup for a methodDesc call or do a direct call
2181 // we need this frame to keep things straight.
2182 //------------------------------------------------------------------------
2184 class StubDispatchFrame : public FramedMethodFrame
2186 VPTR_VTABLE_CLASS(StubDispatchFrame, FramedMethodFrame)
2188 // Representative MethodTable * and slot. They are used to
2189 // compute the MethodDesc* lazily
2190 PTR_MethodTable m_pRepresentativeMT;
2191 UINT32 m_representativeSlot;
2193 // Indirection cell and containing module. Used to compute pGCRefMap lazily.
2194 PTR_Module m_pZapModule;
2195 TADDR m_pIndirection;
2197 // Cached pointer to native ref data.
2198 PTR_BYTE m_pGCRefMap;
2201 StubDispatchFrame(TransitionBlock * pTransitionBlock);
2203 MethodDesc* GetFunction();
2205 // Returns this frame GC ref map if it has one
2206 PTR_BYTE GetGCRefMap();
2209 virtual void UpdateRegDisplay(const PREGDISPLAY pRD);
2210 virtual PCODE GetReturnAddress();
2211 #endif // _TARGET_X86_
2213 PCODE GetUnadjustedReturnAddress()
2215 LIMITED_METHOD_DAC_CONTRACT;
2216 return FramedMethodFrame::GetReturnAddress();
2219 virtual void GcScanRoots(promote_func *fn, ScanContext* sc);
2221 #ifndef DACCESS_COMPILE
2222 void SetRepresentativeSlot(MethodTable * pMT, UINT32 representativeSlot)
2224 LIMITED_METHOD_CONTRACT;
2226 m_pRepresentativeMT = pMT;
2227 m_representativeSlot = representativeSlot;
2230 void SetCallSite(Module * pZapModule, TADDR pIndirection)
2232 LIMITED_METHOD_CONTRACT;
2234 m_pZapModule = pZapModule;
2235 m_pIndirection = pIndirection;
2238 void SetForNullReferenceException()
2240 LIMITED_METHOD_CONTRACT;
2242 // Nothing to do. Everything is initialized in Init.
2246 BOOL TraceFrame(Thread *thread, BOOL fromPatch,
2247 TraceDestination *trace, REGDISPLAY *regs);
2251 LIMITED_METHOD_CONTRACT;
2255 Interception GetInterception();
2258 friend class VirtualCallStubManager;
2260 // Keep as last entry in class
2261 DEFINE_VTABLE_GETTER_AND_CTOR_AND_DTOR(StubDispatchFrame)
2264 typedef VPTR(class StubDispatchFrame) PTR_StubDispatchFrame;
2267 //------------------------------------------------------------------------
2268 // This represents a call from an ExternalMethodThunk or a VirtualImportThunk
2269 // Because the resolving of the target address can do gc and/or
2270 // throw exceptions we need this frame to report the gc references.
2271 //------------------------------------------------------------------------
2273 class ExternalMethodFrame : public FramedMethodFrame
2275 VPTR_VTABLE_CLASS(ExternalMethodFrame, FramedMethodFrame)
2277 // Indirection and containing module. Used to compute pGCRefMap lazily.
2278 PTR_Module m_pZapModule;
2279 TADDR m_pIndirection;
2281 // Cached pointer to native ref data.
2282 PTR_BYTE m_pGCRefMap;
2285 ExternalMethodFrame(TransitionBlock * pTransitionBlock);
2287 virtual void GcScanRoots(promote_func *fn, ScanContext* sc);
2289 // Returns this frame GC ref map if it has one
2290 PTR_BYTE GetGCRefMap();
2292 #ifndef DACCESS_COMPILE
2293 void SetCallSite(Module * pZapModule, TADDR pIndirection)
2295 LIMITED_METHOD_CONTRACT;
2297 m_pZapModule = pZapModule;
2298 m_pIndirection = pIndirection;
2304 LIMITED_METHOD_CONTRACT;
2308 Interception GetInterception();
2311 virtual void UpdateRegDisplay(const PREGDISPLAY pRD);
2314 // Keep as last entry in class
2315 DEFINE_VTABLE_GETTER_AND_CTOR_AND_DTOR(ExternalMethodFrame)
2318 typedef VPTR(class ExternalMethodFrame) PTR_ExternalMethodFrame;
2320 #ifdef FEATURE_READYTORUN
2321 class DynamicHelperFrame : public FramedMethodFrame
2323 VPTR_VTABLE_CLASS(DynamicHelperFrame, FramedMethodFrame)
2325 int m_dynamicHelperFrameFlags;
2328 DynamicHelperFrame(TransitionBlock * pTransitionBlock, int dynamicHelperFrameFlags);
2330 virtual void GcScanRoots(promote_func *fn, ScanContext* sc);
2333 virtual void UpdateRegDisplay(const PREGDISPLAY pRD);
2336 virtual ETransitionType GetTransitionType()
2338 LIMITED_METHOD_DAC_CONTRACT;
2339 return TT_InternalCall;
2342 // Keep as last entry in class
2343 DEFINE_VTABLE_GETTER_AND_CTOR_AND_DTOR(DynamicHelperFrame)
2346 typedef VPTR(class DynamicHelperFrame) PTR_DynamicHelperFrame;
2347 #endif // FEATURE_READYTORUN
2349 //------------------------------------------------------------------------
2350 // This frame is used for instantiating stubs when the argument transform
2351 // is too complex to generate a tail-calling stub.
2352 //------------------------------------------------------------------------
2353 #if !defined(_TARGET_X86_)
2354 class StubHelperFrame : public TransitionFrame
2356 friend class CheckAsmOffsets;
2357 friend class StubLinkerCPU;
2359 VPTR_VTABLE_CLASS(StubHelperFrame, TransitionFrame)
2360 VPTR_UNIQUE(VPTR_UNIQUE_StubHelperFrame)
2362 TransitionBlock m_TransitionBlock;
2364 virtual TADDR GetTransitionBlock()
2366 LIMITED_METHOD_DAC_CONTRACT;
2367 return PTR_HOST_MEMBER_TADDR(StubHelperFrame, this,
2371 static int GetOffsetOfTransitionBlock()
2373 LIMITED_METHOD_DAC_CONTRACT;
2374 return offsetof(StubHelperFrame, m_TransitionBlock);
2378 // Keep as last entry in class
2379 DEFINE_VTABLE_GETTER_AND_CTOR_AND_DTOR(StubHelperFrame)
2381 #endif // _TARGET_X86_
2383 #ifdef FEATURE_COMINTEROP
2385 //------------------------------------------------------------------------
2386 // This represents a com to com+ call method prestub.
2387 // we need to catch exceptions etc. so this frame is not the same
2388 // as the prestub method frame
2389 // Note that in rare IJW cases, the immediate caller could be a managed method
2390 // which pinvoke-inlined a call to a COM interface, which happenned to be
2391 // implemented by a managed function via COM-interop.
2392 //------------------------------------------------------------------------
2393 class ComPrestubMethodFrame : public ComMethodFrame
2395 friend class CheckAsmOffsets;
2397 VPTR_VTABLE_CLASS(ComPrestubMethodFrame, ComMethodFrame)
2400 // Set the vptr and GSCookie
2405 LIMITED_METHOD_DAC_CONTRACT;
2406 return TYPE_INTERCEPTION;
2409 // ComPrestubMethodFrame should return the same interception type as
2410 // code:PrestubMethodFrame.GetInterception.
2411 virtual Interception GetInterception()
2413 LIMITED_METHOD_DAC_CONTRACT;
2414 return INTERCEPTION_PRESTUB;
2417 // Our base class is a a M2U TransitionType; but we're not. So override and set us back to None.
2418 virtual ETransitionType GetTransitionType()
2420 LIMITED_METHOD_DAC_CONTRACT;
2424 virtual void ExceptionUnwind()
2429 // Keep as last entry in class
2430 DEFINE_VTABLE_GETTER_AND_CTOR_AND_DTOR(ComPrestubMethodFrame)
2433 #endif // FEATURE_COMINTEROP
2436 //------------------------------------------------------------------------
2437 // This frame protects object references for the EE's convenience.
2438 // This frame type actually is created from C++.
2439 //------------------------------------------------------------------------
2440 class GCFrame : public Frame
2442 VPTR_VTABLE_CLASS(GCFrame, Frame)
2447 //--------------------------------------------------------------------
2448 // This constructor pushes a new GCFrame on the frame chain.
2449 //--------------------------------------------------------------------
2450 #ifndef DACCESS_COMPILE
2452 LIMITED_METHOD_CONTRACT;
2455 GCFrame(OBJECTREF *pObjRefs, UINT numObjRefs, BOOL maybeInterior);
2456 GCFrame(Thread *pThread, OBJECTREF *pObjRefs, UINT numObjRefs, BOOL maybeInterior);
2458 void Init(Thread *pThread, OBJECTREF *pObjRefs, UINT numObjRefs, BOOL maybeInterior);
2461 //--------------------------------------------------------------------
2462 // Pops the GCFrame and cancels the GC protection. Also
2463 // trashes the contents of pObjRef's in _DEBUG.
2464 //--------------------------------------------------------------------
2467 virtual void GcScanRoots(promote_func *fn, ScanContext* sc);
2470 virtual BOOL Protects(OBJECTREF *ppORef)
2472 LIMITED_METHOD_CONTRACT;
2473 for (UINT i = 0; i < m_numObjRefs; i++) {
2474 if (ppORef == m_pObjRefs + i) {
2482 #ifndef DACCESS_COMPILE
2483 void *operator new (size_t sz, void* p)
2485 LIMITED_METHOD_CONTRACT;
2490 #if defined(_DEBUG_IMPL)
2491 const char* GetFrameTypeName() { LIMITED_METHOD_CONTRACT; return "GCFrame"; }
2495 PTR_OBJECTREF m_pObjRefs;
2497 PTR_Thread m_pCurThread;
2498 BOOL m_MaybeInterior;
2500 // Keep as last entry in class
2501 DEFINE_VTABLE_GETTER_AND_DTOR(GCFrame)
2504 #ifdef FEATURE_INTERPRETER
2505 class InterpreterFrame: public Frame
2507 VPTR_VTABLE_CLASS(InterpreterFrame, Frame)
2509 class Interpreter* m_interp;
2513 #ifndef DACCESS_COMPILE
2514 InterpreterFrame(class Interpreter* interp);
2516 class Interpreter* GetInterpreter() { return m_interp; }
2519 virtual void GcScanRoots(promote_func *fn, ScanContext* sc);
2521 MethodDesc* GetFunction();
2524 DEFINE_VTABLE_GETTER_AND_DTOR(InterpreterFrame)
2528 typedef VPTR(class InterpreterFrame) PTR_InterpreterFrame;
2529 #endif // FEATURE_INTERPRETER
2532 //-----------------------------------------------------------------------------
2535 typedef DPTR(ByRefInfo) PTR_ByRefInfo;
2539 PTR_ByRefInfo pNext;
2542 TypeHandle typeHandle;
2546 //-----------------------------------------------------------------------------
2547 // ProtectByRefsFrame
2548 //-----------------------------------------------------------------------------
2550 class ProtectByRefsFrame : public Frame
2552 VPTR_VTABLE_CLASS(ProtectByRefsFrame, Frame)
2555 #ifndef DACCESS_COMPILE
2556 ProtectByRefsFrame(Thread *pThread, ByRefInfo *brInfo)
2559 WRAPPER_NO_CONTRACT;
2560 Frame::Push(pThread);
2564 virtual void GcScanRoots(promote_func *fn, ScanContext *sc);
2567 PTR_ByRefInfo m_brInfo;
2569 // Keep as last entry in class
2570 DEFINE_VTABLE_GETTER_AND_CTOR_AND_DTOR(ProtectByRefsFrame)
2574 //-----------------------------------------------------------------------------
2576 struct ValueClassInfo;
2577 typedef DPTR(struct ValueClassInfo) PTR_ValueClassInfo;
2579 struct ValueClassInfo
2581 PTR_ValueClassInfo pNext;
2582 PTR_MethodTable pMT;
2585 ValueClassInfo(PTR_VOID aData, PTR_MethodTable aMT, PTR_ValueClassInfo aNext)
2586 : pNext(aNext), pMT(aMT), pData(aData)
2591 //-----------------------------------------------------------------------------
2592 // ProtectValueClassFrame
2593 //-----------------------------------------------------------------------------
2596 class ProtectValueClassFrame : public Frame
2598 VPTR_VTABLE_CLASS(ProtectValueClassFrame, Frame)
2601 #ifndef DACCESS_COMPILE
2602 ProtectValueClassFrame()
2605 WRAPPER_NO_CONTRACT;
2609 ProtectValueClassFrame(Thread *pThread, ValueClassInfo *vcInfo)
2612 WRAPPER_NO_CONTRACT;
2613 Frame::Push(pThread);
2617 virtual void GcScanRoots(promote_func *fn, ScanContext *sc);
2619 ValueClassInfo ** GetValueClassInfoList()
2621 LIMITED_METHOD_CONTRACT;
2627 ValueClassInfo *m_pVCInfo;
2629 // Keep as last entry in class
2630 DEFINE_VTABLE_GETTER_AND_DTOR(ProtectValueClassFrame)
2635 BOOL IsProtectedByGCFrame(OBJECTREF *ppObjectRef);
2639 //------------------------------------------------------------------------
2640 // DebuggerClassInitMarkFrame is a small frame whose only purpose in
2641 // life is to mark for the debugger that "class initialization code" is
2642 // being run. It does nothing useful except return good values from
2643 // GetFrameType and GetInterception.
2644 //------------------------------------------------------------------------
2646 class DebuggerClassInitMarkFrame : public Frame
2648 VPTR_VTABLE_CLASS(DebuggerClassInitMarkFrame, Frame)
2652 #ifndef DACCESS_COMPILE
2653 DebuggerClassInitMarkFrame()
2655 WRAPPER_NO_CONTRACT;
2660 virtual int GetFrameType()
2662 LIMITED_METHOD_DAC_CONTRACT;
2663 return TYPE_INTERCEPTION;
2666 virtual Interception GetInterception()
2668 LIMITED_METHOD_DAC_CONTRACT;
2669 return INTERCEPTION_CLASS_INIT;
2672 // Keep as last entry in class
2673 DEFINE_VTABLE_GETTER_AND_DTOR(DebuggerClassInitMarkFrame)
2677 //------------------------------------------------------------------------
2678 // DebuggerSecurityCodeMarkFrame is a small frame whose only purpose in
2679 // life is to mark for the debugger that "security code" is
2680 // being run. It does nothing useful except return good values from
2681 // GetFrameType and GetInterception.
2682 //------------------------------------------------------------------------
2684 class DebuggerSecurityCodeMarkFrame : public Frame
2686 VPTR_VTABLE_CLASS(DebuggerSecurityCodeMarkFrame, Frame)
2689 #ifndef DACCESS_COMPILE
2690 DebuggerSecurityCodeMarkFrame()
2692 WRAPPER_NO_CONTRACT;
2697 virtual int GetFrameType()
2699 LIMITED_METHOD_DAC_CONTRACT;
2700 return TYPE_INTERCEPTION;
2703 virtual Interception GetInterception()
2705 LIMITED_METHOD_DAC_CONTRACT;
2706 return INTERCEPTION_SECURITY;
2709 // Keep as last entry in class
2710 DEFINE_VTABLE_GETTER_AND_DTOR(DebuggerSecurityCodeMarkFrame)
2713 //------------------------------------------------------------------------
2714 // DebuggerExitFrame is a small frame whose only purpose in
2715 // life is to mark for the debugger that there is an exit transiton on
2716 // the stack. This is special cased for the "break" IL instruction since
2717 // it is an fcall using a helper frame which returns TYPE_CALL instead of
2718 // an ecall (as in System.Diagnostics.Debugger.Break()) which returns
2719 // TYPE_EXIT. This just makes the two consistent for debugging services.
2720 //------------------------------------------------------------------------
2722 class DebuggerExitFrame : public Frame
2724 VPTR_VTABLE_CLASS(DebuggerExitFrame, Frame)
2727 #ifndef DACCESS_COMPILE
2730 WRAPPER_NO_CONTRACT;
2735 virtual int GetFrameType()
2737 LIMITED_METHOD_DAC_CONTRACT;
2741 // Return information about an unmanaged call the frame
2743 // ip - the unmanaged routine which will be called
2744 // returnIP - the address in the stub which the unmanaged routine
2746 // returnSP - the location returnIP is pushed onto the stack
2749 virtual void GetUnmanagedCallSite(TADDR* ip,
2753 LIMITED_METHOD_CONTRACT;
2764 // Keep as last entry in class
2765 DEFINE_VTABLE_GETTER_AND_DTOR(DebuggerExitFrame)
2768 //---------------------------------------------------------------------------------------
2770 // DebuggerU2MCatchHandlerFrame is a small frame whose only purpose in life is to mark for the debugger
2771 // that there is catch handler inside the runtime which may catch and swallow managed exceptions. The
2772 // debugger needs this frame to send a CatchHandlerFound (CHF) notification. Without this frame, the
2773 // debugger doesn't know where a managed exception is caught.
2776 // Currently this frame is only used in code:DispatchInfo.InvokeMember, which is an U2M transition.
2779 class DebuggerU2MCatchHandlerFrame : public Frame
2781 VPTR_VTABLE_CLASS(DebuggerU2MCatchHandlerFrame, Frame)
2784 #ifndef DACCESS_COMPILE
2785 DebuggerU2MCatchHandlerFrame()
2787 WRAPPER_NO_CONTRACT;
2791 DebuggerU2MCatchHandlerFrame(Thread * pThread)
2793 WRAPPER_NO_CONTRACT;
2794 Frame::Push(pThread);
2798 ETransitionType GetTransitionType()
2800 LIMITED_METHOD_DAC_CONTRACT;
2804 // Keep as last entry in class
2805 DEFINE_VTABLE_GETTER_AND_DTOR(DebuggerU2MCatchHandlerFrame)
2809 class UMThunkMarshInfo;
2810 typedef DPTR(class UMThunkMarshInfo) PTR_UMThunkMarshInfo;
2813 typedef DPTR(class UMEntryThunk) PTR_UMEntryThunk;
2815 #if defined(_TARGET_X86_)
2816 //------------------------------------------------------------------------
2817 // This frame guards an unmanaged->managed transition thru a UMThk
2818 //------------------------------------------------------------------------
2820 class UMThkCallFrame : public UnmanagedToManagedFrame
2822 VPTR_VTABLE_CLASS(UMThkCallFrame, UnmanagedToManagedFrame)
2826 #ifdef DACCESS_COMPILE
2827 virtual void EnumMemoryRegions(CLRDataEnumMemoryFlags flags);
2830 PTR_UMEntryThunk GetUMEntryThunk();
2832 static int GetOffsetOfUMEntryThunk()
2834 WRAPPER_NO_CONTRACT;
2835 return GetOffsetOfDatum();
2840 // Keep as last entry in class
2841 DEFINE_VTABLE_GETTER_AND_CTOR_AND_DTOR(UMThkCallFrame)
2843 #endif // _TARGET_X86_ && !FEATURE_PAL
2845 #if defined(_TARGET_X86_) && defined(FEATURE_COMINTEROP)
2846 //-------------------------------------------------------------------------
2847 // Exception handler for COM to managed frame
2848 // and the layout of the exception registration record structure in the stack
2849 // the layout is similar to the NT's EXCEPTIONREGISTRATION record
2850 // followed by the UnmanagedToManagedFrame specific info
2852 struct ComToManagedExRecord
2854 EXCEPTION_REGISTRATION_RECORD m_ExReg;
2855 ArgumentRegisters m_argRegs;
2856 GSCookie m_gsCookie;
2857 UMThkCallFrame m_frame;
2859 UnmanagedToManagedFrame * GetCurrFrame()
2861 LIMITED_METHOD_CONTRACT;
2865 #endif // _TARGET_X86_ && FEATURE_COMINTEROP
2868 //------------------------------------------------------------------------
2869 // This frame is pushed by any JIT'ted method that contains one or more
2870 // inlined N/Direct calls. Note that the JIT'ted method keeps it pushed
2871 // the whole time to amortize the pushing cost across the entire method.
2872 //------------------------------------------------------------------------
2874 typedef DPTR(class InlinedCallFrame) PTR_InlinedCallFrame;
2876 class InlinedCallFrame : public Frame
2878 VPTR_VTABLE_CLASS(InlinedCallFrame, Frame)
2881 virtual MethodDesc *GetFunction()
2883 WRAPPER_NO_CONTRACT;
2884 if (FrameHasActiveCall(this) && HasFunction())
2885 return PTR_MethodDesc(m_Datum);
2892 WRAPPER_NO_CONTRACT;
2895 return ((m_Datum != NULL) && !(dac_cast<TADDR>(m_Datum) & 0x1));
2897 return ((dac_cast<TADDR>(m_Datum) & ~0xffff) != 0);
2901 // Retrieves the return address into the code that called out
2903 virtual TADDR GetReturnAddressPtr()
2905 WRAPPER_NO_CONTRACT;
2907 if (FrameHasActiveCall(this))
2908 return PTR_HOST_MEMBER_TADDR(InlinedCallFrame, this,
2909 m_pCallerReturnAddress);
2914 virtual BOOL NeedsUpdateRegDisplay()
2916 WRAPPER_NO_CONTRACT;
2917 return FrameHasActiveCall(this);
2920 // Given a methodDesc representing an ILStub for a pinvoke call,
2921 // this method will return the MethodDesc for the actual interop
2922 // method if the current InlinedCallFrame is inactive.
2923 PTR_MethodDesc GetActualInteropMethodDesc()
2925 #if defined(_TARGET_X86_) || defined(_TARGET_ARM_)
2926 // Important: This code relies on the way JIT lays out frames. Keep it in sync
2927 // with code:Compiler.lvaAssignFrameOffsets.
2930 // +--------------------+
2931 // | lvaStubArgumentVar | <= filled with EAX in prolog |
2932 // +--------------------+ |
2934 // | InlinedCallFrame | |
2935 // | | <= m_pCrawl.pFrame | to lower addresses
2936 // +--------------------+ V
2939 // Extract the actual MethodDesc to report from the InlinedCallFrame.
2940 TADDR addr = dac_cast<TADDR>(this) + sizeof(InlinedCallFrame);
2941 return PTR_MethodDesc(*PTR_TADDR(addr));
2942 #elif defined(_WIN64)
2943 // On 64bit, the actual interop MethodDesc is saved off in a field off the InlinedCrawlFrame
2944 // which is populated by the JIT. Refer to JIT_InitPInvokeFrame for details.
2945 return PTR_MethodDesc(m_StubSecretArg);
2947 _ASSERTE(!"NYI - Interop method reporting for this architecture!");
2949 #endif // defined(_TARGET_X86_) || defined(_TARGET_ARM_)
2952 virtual void UpdateRegDisplay(const PREGDISPLAY);
2954 // m_Datum contains MethodDesc ptr or
2955 // - on AMD64: CALLI target address (if lowest bit is set)
2956 // - on X86: argument stack size (if value is <64k)
2957 // See code:HasFunction.
2958 PTR_NDirectMethodDesc m_Datum;
2961 // IL stubs fill this field with the incoming secret argument when they erect
2962 // InlinedCallFrame so we know which interop method was invoked even if the frame
2963 // is not active at the moment.
2964 PTR_VOID m_StubSecretArg;
2968 // X86: ESP after pushing the outgoing arguments, and just before calling
2969 // out to unmanaged code.
2970 // Other platforms: the field stays set throughout the declaring method.
2971 PTR_VOID m_pCallSiteSP;
2973 // EIP where the unmanaged call will return to. This will be a pointer into
2974 // the code of the managed frame which has the InlinedCallFrame
2975 // This is set to NULL in the method prolog. It gets set just before the
2976 // call to the target and reset back to NULL after the stop-for-GC check
2977 // following the call.
2978 TADDR m_pCallerReturnAddress;
2980 // This is used only for EBP. Hence, a stackwalk will miss the other
2981 // callee-saved registers for the method with the InlinedCallFrame.
2982 // To prevent GC-holes, we do not keep any GC references in callee-saved
2983 // registers across an NDirect call.
2984 TADDR m_pCalleeSavedFP;
2987 //---------------------------------------------------------------
2988 // Expose key offsets and values for stub generation.
2989 //---------------------------------------------------------------
2991 static void GetEEInfo(CORINFO_EE_INFO::InlinedCallFrameInfo * pEEInfo);
2993 // Is the specified frame an InlinedCallFrame which has an active call
2994 // inside it right now?
2995 static BOOL FrameHasActiveCall(Frame *pFrame)
2997 WRAPPER_NO_CONTRACT;
3000 pFrame != FRAME_TOP &&
3001 InlinedCallFrame::GetMethodFrameVPtr() == pFrame->GetVTablePtr() &&
3002 dac_cast<TADDR>(dac_cast<PTR_InlinedCallFrame>(pFrame)->m_pCallerReturnAddress) != NULL;
3005 // Marks the frame as inactive.
3008 m_pCallerReturnAddress = NULL;
3013 LIMITED_METHOD_DAC_CONTRACT;
3017 virtual BOOL IsTransitionToNativeFrame()
3019 LIMITED_METHOD_CONTRACT;
3023 PTR_VOID GetCallSiteSP()
3025 LIMITED_METHOD_CONTRACT;
3026 return m_pCallSiteSP;
3029 TADDR GetCalleeSavedFP()
3031 LIMITED_METHOD_DAC_CONTRACT;
3032 return m_pCalleeSavedFP;
3035 // Set the vptr and GSCookie
3038 // Keep as last entry in class
3039 DEFINE_VTABLE_GETTER_AND_CTOR_AND_DTOR(InlinedCallFrame)
3042 //------------------------------------------------------------------------
3043 // This frame is used to mark a Context/AppDomain Transition
3044 //------------------------------------------------------------------------
3046 class ContextTransitionFrame : public Frame
3049 PTR_Context m_pReturnContext;
3050 PTR_Object m_ReturnExecutionContext;
3051 PTR_Object m_LastThrownObjectInParentContext;
3052 ULONG_PTR m_LockCount; // Number of locks the thread takes
3053 // before the transition.
3054 VPTR_VTABLE_CLASS(ContextTransitionFrame, Frame)
3057 virtual void GcScanRoots(promote_func *fn, ScanContext* sc);
3059 virtual PTR_Context* GetReturnContextAddr()
3061 LIMITED_METHOD_DAC_CONTRACT;
3062 return &m_pReturnContext;
3065 virtual Object **GetReturnExecutionContextAddr()
3067 LIMITED_METHOD_CONTRACT;
3068 return (Object **) &m_ReturnExecutionContext;
3071 OBJECTREF GetLastThrownObjectInParentContext()
3073 return ObjectToOBJECTREF(m_LastThrownObjectInParentContext);
3076 void SetLastThrownObjectInParentContext(OBJECTREF lastThrownObject)
3078 m_LastThrownObjectInParentContext = OBJECTREFToObject(lastThrownObject);
3081 void SetLockCount(DWORD lockCount)
3083 LIMITED_METHOD_CONTRACT;
3084 m_LockCount = lockCount;
3086 DWORD GetLockCount()
3088 LIMITED_METHOD_CONTRACT;
3089 return (DWORD) m_LockCount;
3093 // Let debugger know that we're transitioning between AppDomains.
3094 ETransitionType GetTransitionType()
3096 LIMITED_METHOD_DAC_CONTRACT;
3097 return TT_AppDomain;
3100 #ifndef DACCESS_COMPILE
3101 ContextTransitionFrame()
3102 : m_pReturnContext(NULL)
3103 , m_ReturnExecutionContext(NULL)
3104 , m_LastThrownObjectInParentContext(NULL)
3107 LIMITED_METHOD_CONTRACT;
3111 // Keep as last entry in class
3112 DEFINE_VTABLE_GETTER_AND_DTOR(ContextTransitionFrame)
3115 // TODO [DAVBR]: For the full fix for VsWhidbey 450273, this
3116 // may be uncommented once isLegalManagedCodeCaller works properly
3117 // with non-return address inputs, and with non-DEBUG builds
3118 //bool isLegalManagedCodeCaller(TADDR retAddr);
3119 bool isRetAddr(TADDR retAddr, TADDR* whereCalled);
3121 //------------------------------------------------------------------------
3123 // This frame is used as padding for virtual stub dispatch tailcalls.
3124 // When A calls B via virtual stub dispatch, the stub dispatch stub resolves
3125 // the target code for B and jumps to it. If A wants to do a tail call,
3126 // it does not get a chance to unwind its frame since the virtual stub dispatch
3127 // stub is not set up to return the address of the target code (rather
3128 // than just jumping to it).
3129 // To do a tail call, A calls JIT_TailCall, which unwinds A's frame
3130 // and sets up a TailCallFrame. It then calls the stub dispatch stub
3131 // which disassembles the caller (JIT_TailCall, in this case) to get some information,
3132 // resolves the target code for B, and then jumps to B.
3133 // If B also does a virtual stub dispatch tail call, then we reuse the
3134 // existing TailCallFrame instead of setting up a second one.
3136 // We could eliminate TailCallFrame if we factor the VSD stub to return
3137 // the target code address. This is currently not a very important scenario
3138 // as tail calls on interface calls are uncommon.
3140 // This frame is used as padding for tailcalls which require more space
3141 // than the caller has in it's incoming argument space.
3142 // To do a tail call from A to B, A calls JIT_TailCall, which unwinds A's frame
3143 // and sets up a TailCallFrame and the arguments. It then jumps to B.
3144 // If B also does a tail call, then we reuse the
3145 // existing TailCallFrame instead of setting up a second one.
3147 // This is also used whenever value types that aren't enregisterable are
3148 // passed by value instead of ref. This is currently not a very important
3149 // scenario as tail calls are uncommon.
3151 //------------------------------------------------------------------------
3153 class TailCallFrame : public Frame
3155 VPTR_VTABLE_CLASS(TailCallFrame, Frame)
3157 #if defined(_TARGET_X86_)
3158 TADDR m_CallerAddress; // the address the tailcall was initiated from
3159 CalleeSavedRegisters m_regs; // callee saved registers - the stack walk assumes that all non-JIT frames have them
3160 TADDR m_ReturnAddress; // the return address of the tailcall
3161 #elif defined(_TARGET_AMD64_)
3163 TADDR m_padding; // code:StubLinkerCPU::CreateTailCallCopyArgsThunk expects the size of TailCallFrame to be 16-byte aligned
3164 CalleeSavedRegisters m_calleeSavedRegisters;
3165 TADDR m_ReturnAddress;
3166 #elif defined(_TARGET_ARM_)
3168 CalleeSavedRegisters m_calleeSavedRegisters;
3169 // alias saved link register as m_ReturnAddress
3171 INT32 r4, r5, r6, r7, r8, r9, r10;
3173 TADDR m_ReturnAddress;
3177 TADDR m_ReturnAddress;
3181 #ifndef CROSSGEN_COMPILE
3182 #if !defined(_TARGET_X86_)
3184 #ifndef DACCESS_COMPILE
3185 TailCallFrame(T_CONTEXT * pContext, Thread * pThread)
3187 InitFromContext(pContext);
3188 m_Next = pThread->GetFrame();
3191 void InitFromContext(T_CONTEXT * pContext);
3193 // Architecture-specific method to initialize a CONTEXT record as if the first
3194 // part of the TailCallHelperStub had executed
3195 static TailCallFrame * AdjustContextForTailCallHelperStub(_CONTEXT * pContext, size_t cbNewArgArea, Thread * pThread);
3198 static TailCallFrame * GetFrameFromContext(CONTEXT * pContext);
3199 #endif // !_TARGET_X86_
3201 #if defined(_TARGET_X86_)
3202 static TailCallFrame* FindTailCallFrame(Frame* pFrame)
3204 LIMITED_METHOD_CONTRACT;
3205 // loop through the frame chain
3206 while (pFrame->GetVTablePtr() != TailCallFrame::GetMethodFrameVPtr())
3207 pFrame = pFrame->m_Next;
3208 return (TailCallFrame*)pFrame;
3211 TADDR GetCallerAddress()
3213 LIMITED_METHOD_CONTRACT;
3214 return m_CallerAddress;
3216 #endif // _TARGET_X86_
3218 virtual TADDR GetReturnAddressPtr()
3220 LIMITED_METHOD_DAC_CONTRACT;
3221 return PTR_HOST_MEMBER_TADDR(TailCallFrame, this,
3225 virtual BOOL NeedsUpdateRegDisplay()
3230 virtual void UpdateRegDisplay(const PREGDISPLAY pRD);
3231 #endif // !CROSSGEN_COMPILE
3232 #ifdef _TARGET_AMD64_
3233 void SetGCLayout(TADDR pGCLayout)
3235 LIMITED_METHOD_CONTRACT;
3236 m_pGCLayout = pGCLayout;
3239 virtual void GcScanRoots(promote_func *fn, ScanContext* sc);
3241 void SetGCLayout(TADDR pGCLayout)
3243 LIMITED_METHOD_CONTRACT;
3244 _ASSERTE(pGCLayout == NULL);
3249 // Keep as last entry in class
3250 DEFINE_VTABLE_GETTER_AND_CTOR_AND_DTOR(TailCallFrame)
3253 //------------------------------------------------------------------------
3254 // ExceptionFilterFrame is a small frame whose only purpose in
3255 // life is to set SHADOW_SP_FILTER_DONE during unwind from exception filter.
3256 //------------------------------------------------------------------------
3258 class ExceptionFilterFrame : public Frame
3260 VPTR_VTABLE_CLASS(ExceptionFilterFrame, Frame)
3261 size_t* m_pShadowSP;
3264 #ifndef DACCESS_COMPILE
3265 ExceptionFilterFrame(size_t* pShadowSP)
3267 WRAPPER_NO_CONTRACT;
3268 m_pShadowSP = pShadowSP;
3274 // Nothing to do here.
3275 WRAPPER_NO_CONTRACT;
3280 void SetFilterDone()
3282 LIMITED_METHOD_CONTRACT;
3284 // Mark the filter as having completed
3287 // Make sure that CallJitEHFilterHelper marked us as being in the filter.
3288 _ASSERTE(*m_pShadowSP & ICodeManager::SHADOW_SP_IN_FILTER);
3289 *m_pShadowSP |= ICodeManager::SHADOW_SP_FILTER_DONE;
3295 // Keep as last entry in class
3296 DEFINE_VTABLE_GETTER_AND_CTOR_AND_DTOR(ExceptionFilterFrame)
3300 // We use IsProtectedByGCFrame to check if some OBJECTREF pointers are protected
3301 // against GC. That function doesn't know if a byref is from managed stack thus
3302 // protected by JIT. AssumeByrefFromJITStack is used to bypass that check if an
3303 // OBJECTRef pointer is passed from managed code to an FCall and it's in stack.
3304 class AssumeByrefFromJITStack : public Frame
3306 VPTR_VTABLE_CLASS(AssumeByrefFromJITStack, Frame)
3308 #ifndef DACCESS_COMPILE
3309 AssumeByrefFromJITStack(OBJECTREF *pObjRef)
3311 m_pObjRef = pObjRef;
3315 BOOL Protects(OBJECTREF *ppORef)
3317 LIMITED_METHOD_CONTRACT;
3318 return ppORef == m_pObjRef;
3322 OBJECTREF *m_pObjRef;
3324 // Keep as last entry in class
3325 DEFINE_VTABLE_GETTER_AND_DTOR(AssumeByrefFromJITStack)
3326 }; //AssumeByrefFromJITStack
3330 //-----------------------------------------------------------------------------
3331 // FrameWithCookie is used to declare a Frame in source code with a cookie
3332 // immediately preceeding it.
3333 // This is just a specialized version of GSCookieFor<T>
3335 // For Frames that are set up by stubs, the stub is responsible for setting up
3338 // Note that we have to play all these games for the GSCookie as the GSCookie
3339 // needs to precede the vtable pointer, so that the GSCookie is guaranteed to
3340 // catch any stack-buffer-overrun corruptions that overwrite the Frame data.
3342 //-----------------------------------------------------------------------------
3346 class GCSafeCollection;
3348 template <typename FrameType>
3349 class FrameWithCookie
3353 GSCookie m_gsCookie;
3359 // Overload all the required constructors
3363 m_gsCookie(GetProcessGSCookie()), m_frame() { WRAPPER_NO_CONTRACT; }
3365 FrameWithCookie(Thread * pThread) :
3366 m_gsCookie(GetProcessGSCookie()), m_frame(pThread) { WRAPPER_NO_CONTRACT; }
3368 FrameWithCookie(T_CONTEXT * pContext) :
3369 m_gsCookie(GetProcessGSCookie()), m_frame(pContext) { WRAPPER_NO_CONTRACT; }
3371 FrameWithCookie(TransitionBlock * pTransitionBlock) :
3372 m_gsCookie(GetProcessGSCookie()), m_frame(pTransitionBlock) { WRAPPER_NO_CONTRACT; }
3374 FrameWithCookie(TransitionBlock * pTransitionBlock, MethodDesc * pMD) :
3375 m_gsCookie(GetProcessGSCookie()), m_frame(pTransitionBlock, pMD) { WRAPPER_NO_CONTRACT; }
3377 FrameWithCookie(TransitionBlock * pTransitionBlock, VASigCookie * pVASigCookie, PCODE pUnmanagedTarget) :
3378 m_gsCookie(GetProcessGSCookie()), m_frame(pTransitionBlock, pVASigCookie, pUnmanagedTarget) { WRAPPER_NO_CONTRACT; }
3380 FrameWithCookie(TransitionBlock * pTransitionBlock, int frameFlags) :
3381 m_gsCookie(GetProcessGSCookie()), m_frame(pTransitionBlock, frameFlags) { WRAPPER_NO_CONTRACT; }
3385 FrameWithCookie(Thread * pThread, OBJECTREF *pObjRefs, UINT numObjRefs, BOOL maybeInterior) :
3386 m_gsCookie(GetProcessGSCookie()), m_frame(pThread, pObjRefs, numObjRefs, maybeInterior) { WRAPPER_NO_CONTRACT; }
3388 FrameWithCookie(OBJECTREF *pObjRefs, UINT numObjRefs, BOOL maybeInterior) :
3389 m_gsCookie(GetProcessGSCookie()), m_frame(pObjRefs, numObjRefs, maybeInterior) { WRAPPER_NO_CONTRACT; }
3391 // GCSafeCollectionFrame
3392 FrameWithCookie(GCSafeCollection *gcSafeCollection) :
3393 m_gsCookie(GetProcessGSCookie()), m_frame(gcSafeCollection) { WRAPPER_NO_CONTRACT; }
3395 #ifdef FEATURE_INTERPRETER
3397 FrameWithCookie(Interpreter* interp) :
3398 m_gsCookie(GetProcessGSCookie()), m_frame(interp) { WRAPPER_NO_CONTRACT; }
3402 FrameWithCookie(LPVOID returnAddress, Thread *thread, HijackArgs *args) :
3403 m_gsCookie(GetProcessGSCookie()), m_frame(returnAddress, thread, args) { WRAPPER_NO_CONTRACT; }
3405 #ifdef DEBUGGING_SUPPORTED
3407 FrameWithCookie(DebuggerEval *pDebuggerEval, TADDR returnAddress, BOOL showFrame) :
3408 m_gsCookie(GetProcessGSCookie()), m_frame(pDebuggerEval, returnAddress, showFrame) { WRAPPER_NO_CONTRACT; }
3409 #endif // DEBUGGING_SUPPORTED
3412 FrameWithCookie(T_CONTEXT * pContext, Thread *thread) :
3413 m_gsCookie(GetProcessGSCookie()), m_frame(pContext, thread) { WRAPPER_NO_CONTRACT; }
3415 #ifndef DACCESS_COMPILE
3416 // GSCookie for HelperMethodFrames is initialized in a common HelperMethodFrame init method
3418 // HelperMethodFrame
3419 FORCEINLINE FrameWithCookie(void* fCallFtnEntry, unsigned attribs = 0) :
3420 m_frame(fCallFtnEntry, attribs) { WRAPPER_NO_CONTRACT; }
3422 // HelperMethodFrame_1OBJ
3423 FORCEINLINE FrameWithCookie(void* fCallFtnEntry, unsigned attribs, OBJECTREF * aGCPtr1) :
3424 m_frame(fCallFtnEntry, attribs, aGCPtr1) { WRAPPER_NO_CONTRACT; }
3426 // HelperMethodFrame_2OBJ
3427 FORCEINLINE FrameWithCookie(void* fCallFtnEntry, unsigned attribs, OBJECTREF * aGCPtr1, OBJECTREF * aGCPtr2) :
3428 m_frame(fCallFtnEntry, attribs, aGCPtr1, aGCPtr2) { WRAPPER_NO_CONTRACT; }
3430 // HelperMethodFrame_PROTECTOBJ
3431 FORCEINLINE FrameWithCookie(void* fCallFtnEntry, unsigned attribs, OBJECTREF* pObjRefs, int numObjRefs) :
3432 m_frame(fCallFtnEntry, attribs, pObjRefs, numObjRefs) { WRAPPER_NO_CONTRACT; }
3434 #endif // DACCESS_COMPILE
3436 // ProtectByRefsFrame
3437 FrameWithCookie(Thread * pThread, ByRefInfo * pByRefs) :
3438 m_gsCookie(GetProcessGSCookie()), m_frame(pThread, pByRefs) { WRAPPER_NO_CONTRACT; }
3440 // ProtectValueClassFrame
3441 FrameWithCookie(Thread * pThread, ValueClassInfo * pValueClasses) :
3442 m_gsCookie(GetProcessGSCookie()), m_frame(pThread, pValueClasses) { WRAPPER_NO_CONTRACT; }
3444 // ExceptionFilterFrame
3445 FrameWithCookie(size_t* pShadowSP) :
3446 m_gsCookie(GetProcessGSCookie()), m_frame(pShadowSP) { WRAPPER_NO_CONTRACT; }
3449 // AssumeByrefFromJITStack
3450 FrameWithCookie(OBJECTREF *pObjRef) :
3451 m_gsCookie(GetProcessGSCookie()), m_frame(pObjRef) { WRAPPER_NO_CONTRACT; }
3453 void SetAddrOfHaveCheckedRestoreState(BOOL* pDoneCheck)
3455 WRAPPER_NO_CONTRACT;
3456 m_frame.SetAddrOfHaveCheckedRestoreState(pDoneCheck);
3462 // Overload some common Frame methods for easy redirection
3465 void Push() { WRAPPER_NO_CONTRACT; m_frame.Push(); }
3466 void Pop() { WRAPPER_NO_CONTRACT; m_frame.Pop(); }
3467 void Push(Thread * pThread) { WRAPPER_NO_CONTRACT; m_frame.Push(pThread); }
3468 void Pop(Thread * pThread) { WRAPPER_NO_CONTRACT; m_frame.Pop(pThread); }
3469 PCODE GetReturnAddress() { WRAPPER_NO_CONTRACT; return m_frame.GetReturnAddress(); }
3470 T_CONTEXT * GetContext() { WRAPPER_NO_CONTRACT; return m_frame.GetContext(); }
3471 FrameType* operator&() { LIMITED_METHOD_CONTRACT; return &m_frame; }
3472 LazyMachState * MachineState() { WRAPPER_NO_CONTRACT; return m_frame.MachineState(); }
3473 Thread * GetThread() { WRAPPER_NO_CONTRACT; return m_frame.GetThread(); }
3474 BOOL InsureInit(bool initialInit, struct MachState* unwindState)
3475 { WRAPPER_NO_CONTRACT; return m_frame.InsureInit(initialInit, unwindState); }
3476 void Poll() { WRAPPER_NO_CONTRACT; m_frame.Poll(); }
3477 void SetStackPointerPtr(TADDR sp) { WRAPPER_NO_CONTRACT; m_frame.SetStackPointerPtr(sp); }
3478 void InitAndLink(T_CONTEXT *pContext) { WRAPPER_NO_CONTRACT; m_frame.InitAndLink(pContext); }
3479 void Init(Thread *pThread, OBJECTREF *pObjRefs, UINT numObjRefs, BOOL maybeInterior)
3480 { WRAPPER_NO_CONTRACT; m_frame.Init(pThread, pObjRefs, numObjRefs, maybeInterior); }
3481 ValueClassInfo ** GetValueClassInfoList() { WRAPPER_NO_CONTRACT; return m_frame.GetValueClassInfoList(); }
3485 // Access to the underlying Frame
3486 // You should only need to use this if none of the above overloads work for you
3487 // Consider adding the required overload to the list above
3490 FrameType& operator->() { LIMITED_METHOD_CONTRACT; return m_frame; }
3493 // Since the "&" operator is overloaded, use this function to get to the
3494 // address of FrameWithCookie, rather than that of FrameWithCookie::m_frame.
3495 GSCookie * GetGSCookiePtr() { LIMITED_METHOD_CONTRACT; return &m_gsCookie; }
3499 // The frame doesn't represent a transition of any sort, it's simply placed on the stack to represent an assembly that will be found
3500 // and checked by stackwalking security demands. This can be used in scenarios where an assembly is implicitly controlling a
3501 // security sensitive operation without being explicitly represented on the stack. For example, an assembly decorating one of its
3502 // classes or methods with a custom attribute can implicitly cause the ctor or property setters for that attribute to be executed by
3503 // a third party if they happen to browse the attributes on the assembly.
3504 // Note: This frame is pushed from managed code, so be sure to keep the layout synchronized with that in
3505 // bcl\system\reflection\customattribute.cs.
3506 class SecurityContextFrame : public Frame
3508 VPTR_VTABLE_CLASS(SecurityContextFrame, Frame)
3510 Assembly *m_pAssembly;
3513 virtual Assembly *GetAssembly() { LIMITED_METHOD_CONTRACT; return m_pAssembly; }
3515 void SetAssembly(Assembly *pAssembly) { LIMITED_METHOD_CONTRACT; m_pAssembly = pAssembly; }
3517 // Keep as last entry in class
3518 DEFINE_VTABLE_GETTER_AND_CTOR_AND_DTOR(SecurityContextFrame)
3521 //------------------------------------------------------------------------
3522 // These macros GC-protect OBJECTREF pointers on the EE's behalf.
3523 // In between these macros, the GC can move but not discard the protected
3524 // objects. If the GC moves an object, it will update the guarded OBJECTREF's.
3527 // OBJECTREF or = <some valid objectref>;
3528 // GCPROTECT_BEGIN(or);
3530 // ...<do work that can trigger GC>...
3535 // These macros can also protect multiple OBJECTREF's if they're packaged
3536 // into a structure:
3543 // GCPROTECT_BEGIN(gc);
3550 // - GCPROTECT_BEGININTERIOR() can be used in place of GCPROTECT_BEGIN()
3551 // to handle the case where one or more of the OBJECTREFs is potentially
3552 // an interior pointer. This is a rare situation, because boxing would
3553 // normally prevent us from encountering it. Be aware that the OBJECTREFs
3554 // we protect are not validated in this situation.
3556 // - GCPROTECT_ARRAY_BEGIN() can be used when an array of object references
3557 // is allocated on the stack. The pointer to the first element is passed
3558 // along with the number of elements in the array.
3560 // - The argument to GCPROTECT_BEGIN should be an lvalue because it
3561 // uses "sizeof" to count the OBJECTREF's.
3563 // - GCPROTECT_BEGIN spiritually violates our normal convention of not passing
3564 // non-const refernce arguments. Unfortunately, this is necessary in
3565 // order for the sizeof thing to work.
3567 // - GCPROTECT_BEGIN does _not_ zero out the OBJECTREF's. You must have
3568 // valid OBJECTREF's when you invoke this macro.
3570 // - GCPROTECT_BEGIN begins a new C nesting block. Besides allowing
3571 // GCPROTECT_BEGIN's to nest, it also has the advantage of causing
3572 // a compiler error if you forget to code a maching GCPROTECT_END.
3574 // - If you are GCPROTECTing something, it means you are expecting a GC to occur.
3575 // So we assert that GC is not forbidden. If you hit this assert, you probably need
3576 // a HELPER_METHOD_FRAME to protect the region that can cause the GC.
3577 //------------------------------------------------------------------------
3579 #ifndef DACCESS_COMPILE
3582 // Suppress prefast warning #6384: Dividing sizeof a pointer by another value
3583 #pragma warning(disable:6384)
3584 #endif /*_PREFAST_ */
3586 #define GCPROTECT_BEGIN(ObjRefStruct) do { \
3587 FrameWithCookie<GCFrame> __gcframe( \
3588 (OBJECTREF*)&(ObjRefStruct), \
3589 sizeof(ObjRefStruct)/sizeof(OBJECTREF), \
3591 /* work around unreachable code warning */ \
3592 if (true) { DEBUG_ASSURE_NO_RETURN_BEGIN(GCPROTECT)
3594 #define GCPROTECT_BEGIN_THREAD(pThread, ObjRefStruct) do { \
3595 FrameWithCookie<GCFrame> __gcframe( \
3597 (OBJECTREF*)&(ObjRefStruct), \
3598 sizeof(ObjRefStruct)/sizeof(OBJECTREF), \
3600 /* work around unreachable code warning */ \
3601 if (true) { DEBUG_ASSURE_NO_RETURN_BEGIN(GCPROTECT)
3603 #define GCPROTECT_ARRAY_BEGIN(ObjRefArray,cnt) do { \
3604 FrameWithCookie<GCFrame> __gcframe( \
3605 (OBJECTREF*)&(ObjRefArray), \
3606 cnt * sizeof(ObjRefArray) / sizeof(OBJECTREF), \
3608 /* work around unreachable code warning */ \
3609 if (true) { DEBUG_ASSURE_NO_RETURN_BEGIN(GCPROTECT)
3611 #define GCPROTECT_BEGININTERIOR(ObjRefStruct) do { \
3612 FrameWithCookie<GCFrame> __gcframe( \
3613 (OBJECTREF*)&(ObjRefStruct), \
3614 sizeof(ObjRefStruct)/sizeof(OBJECTREF), \
3616 /* work around unreachable code warning */ \
3617 if (true) { DEBUG_ASSURE_NO_RETURN_BEGIN(GCPROTECT)
3619 #define GCPROTECT_BEGININTERIOR_ARRAY(ObjRefArray,cnt) do { \
3620 FrameWithCookie<GCFrame> __gcframe( \
3621 (OBJECTREF*)&(ObjRefArray), \
3624 /* work around unreachable code warning */ \
3625 if (true) { DEBUG_ASSURE_NO_RETURN_BEGIN(GCPROTECT)
3628 #define GCPROTECT_END() \
3629 DEBUG_ASSURE_NO_RETURN_END(GCPROTECT) } \
3630 __gcframe.Pop(); } while(0)
3633 #else // #ifndef DACCESS_COMPILE
3635 #define GCPROTECT_BEGIN(ObjRefStruct)
3636 #define GCPROTECT_ARRAY_BEGIN(ObjRefArray,cnt)
3637 #define GCPROTECT_BEGININTERIOR(ObjRefStruct)
3638 #define GCPROTECT_END()
3640 #endif // #ifndef DACCESS_COMPILE
3643 #define ASSERT_ADDRESS_IN_STACK(address) _ASSERTE (Thread::IsAddressInCurrentStack (address));
3645 #if defined (_DEBUG) && !defined (DACCESS_COMPILE)
3646 #define ASSUME_BYREF_FROM_JIT_STACK_BEGIN(__objRef) \
3647 /* make sure we are only called inside an FCall */ \
3648 if (__me == 0) {}; \
3649 /* make sure the address is in stack. If the address is an interior */ \
3650 /*pointer points to GC heap, the FCall still needs to protect it explicitly */ \
3651 ASSERT_ADDRESS_IN_STACK (__objRef); \
3653 FrameWithCookie<AssumeByrefFromJITStack> __dummyAssumeByrefFromJITStack ((__objRef)); \
3654 __dummyAssumeByrefFromJITStack.Push (); \
3655 /* work around unreachable code warning */ \
3656 if (true) { DEBUG_ASSURE_NO_RETURN_BEGIN(GC_PROTECT)
3658 #define ASSUME_BYREF_FROM_JIT_STACK_END() \
3659 DEBUG_ASSURE_NO_RETURN_END(GC_PROTECT) } \
3660 __dummyAssumeByrefFromJITStack.Pop(); } while(0)
3661 #else //defined (_DEBUG) && !defined (DACCESS_COMPILE)
3662 #define ASSUME_BYREF_FROM_JIT_STACK_BEGIN(__objRef)
3663 #define ASSUME_BYREF_FROM_JIT_STACK_END()
3664 #endif //defined (_DEBUG) && !defined (DACCESS_COMPILE)
3666 //------------------------------------------------------------------------
3668 #if defined(FRAMES_TURNED_FPO_ON)
3669 #pragma optimize("", on) // Go back to command line default optimizations
3670 #undef FRAMES_TURNED_FPO_ON
3674 #endif //__frames_h__