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_3OBJ- reports additional object references
65 // + +-HelperMethodFrame_PROTECTOBJ - reports additional object references
67 // +-TransitionFrame - this abstract frame represents a transition from
68 // | | one or more nested frameless method calls
69 // | | to either a EE runtime helper function or
70 // | | a framed method.
72 // | +-StubHelperFrame - for instantiating stubs that need to grow stack arguments
74 // | +-SecureDelegateFrame - represents a call Delegate.Invoke for secure delegate
76 // | +-MulticastFrame - this frame protects arguments to a MulticastDelegate
77 // | Invoke() call while calling each subscriber.
79 // | +-FramedMethodFrame - this abstract frame represents a call to a method
80 // | | that generates a full-fledged frame.
82 #ifdef FEATURE_COMINTEROP
84 // | +-ComPlusMethodFrame - represents a CLR to COM call using the generic worker
86 #endif //FEATURE_COMINTEROP
88 // | +-PInvokeCalliFrame - protects arguments when a call to GetILStubForCalli is made
89 // | | to get or create IL stub for an unmanaged CALLI
91 // | +-PrestubMethodFrame - represents a call to a prestub
93 // | +-StubDispatchFrame - represents a call into the virtual call stub manager
96 // | +-ExternalMethodFrame - represents a call from an ExternalMethdThunk
98 // | +-TPMethodFrame - for calls on transparent proxy
100 // +-UnmanagedToManagedFrame - this frame represents a transition from
101 // | | unmanaged code back to managed code. It's
102 // | | main functions are to stop COM+ exception
103 // | | propagation and to expose unmanaged parameters.
105 #ifdef FEATURE_COMINTEROP
107 // | +-ComMethodFrame - this frame represents a transition from
110 // | +-ComPrestubMethodFrame - prestub frame for calls from COM to CLR
112 #endif //FEATURE_COMINTEROP
114 // | +-UMThkCallFrame - this frame represents an unmanaged->managed
115 // | transition through N/Direct
118 // +-ContextTransitionFrame - this frame is used to mark an appdomain transition
121 // +-TailCallFrame - padding for tailcalls
123 // +-ProtectByRefsFrame
125 // +-ProtectValueClassFrame
127 // +-DebuggerClassInitMarkFrame - marker frame to indicate that "class init" code is running
129 // +-DebuggerSecurityCodeMarkFrame - marker frame to indicate that security code is running
131 // +-DebuggerExitFrame - marker frame to indicate that a "break" IL instruction is being executed
133 // +-DebuggerU2MCatchHandlerFrame - marker frame to indicate that native code is going to catch and
134 // | swallow a managed exception
136 #ifdef DEBUGGING_SUPPORTED
137 // +-FuncEvalFrame - frame for debugger function evaluation
138 #endif // DEBUGGING_SUPPORTED
141 // +-ExceptionFilterFrame - this frame wraps call to exception filter
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_3OBJ)
221 FRAME_TYPE_NAME(HelperMethodFrame_PROTECTOBJ)
222 FRAME_ABSTRACT_TYPE_NAME(FramedMethodFrame)
223 FRAME_TYPE_NAME(SecureDelegateFrame)
224 FRAME_TYPE_NAME(MulticastFrame)
225 FRAME_ABSTRACT_TYPE_NAME(UnmanagedToManagedFrame)
226 #ifdef FEATURE_COMINTEROP
227 FRAME_TYPE_NAME(ComMethodFrame)
228 FRAME_TYPE_NAME(ComPlusMethodFrame)
229 FRAME_TYPE_NAME(ComPrestubMethodFrame)
230 #endif // FEATURE_COMINTEROP
231 FRAME_TYPE_NAME(PInvokeCalliFrame)
232 #ifdef FEATURE_HIJACK
233 FRAME_TYPE_NAME(HijackFrame)
234 #endif // FEATURE_HIJACK
235 FRAME_TYPE_NAME(PrestubMethodFrame)
236 FRAME_TYPE_NAME(StubDispatchFrame)
237 FRAME_TYPE_NAME(ExternalMethodFrame)
238 #ifdef FEATURE_READYTORUN
239 FRAME_TYPE_NAME(DynamicHelperFrame)
241 #if !defined(_TARGET_X86_)
242 FRAME_TYPE_NAME(StubHelperFrame)
244 FRAME_TYPE_NAME(GCFrame)
245 #ifdef FEATURE_INTERPRETER
246 FRAME_TYPE_NAME(InterpreterFrame)
247 #endif // FEATURE_INTERPRETER
248 FRAME_TYPE_NAME(ProtectByRefsFrame)
249 FRAME_TYPE_NAME(ProtectValueClassFrame)
250 FRAME_TYPE_NAME(DebuggerClassInitMarkFrame)
251 FRAME_TYPE_NAME(DebuggerSecurityCodeMarkFrame)
252 FRAME_TYPE_NAME(DebuggerExitFrame)
253 FRAME_TYPE_NAME(DebuggerU2MCatchHandlerFrame)
255 FRAME_TYPE_NAME(UMThkCallFrame)
257 FRAME_TYPE_NAME(InlinedCallFrame)
258 FRAME_TYPE_NAME(ContextTransitionFrame)
259 FRAME_TYPE_NAME(TailCallFrame)
260 FRAME_TYPE_NAME(ExceptionFilterFrame)
262 FRAME_TYPE_NAME(AssumeByrefFromJITStack)
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
283 #include "siginfo.hpp"
284 #include "method.hpp"
285 #include "stackwalk.h"
289 #include "callingconvention.h"
291 // Forward references
293 class FieldMarshaler;
294 class FramedMethodFrame;
295 typedef VPTR(class FramedMethodFrame) PTR_FramedMethodFrame;
298 class UMThunkMarshInfo;
300 struct ResolveCacheElem;
301 #if defined(DACCESS_COMPILE)
302 class DacDbiInterfaceImpl;
303 #endif // DACCESS_COMPILE
304 #ifdef FEATURE_COMINTEROP
305 class ComMethodFrame;
306 class ComCallMethodDesc;
307 #endif // FEATURE_COMINTEROP
309 // Note: the value (-1) is used to generate the largest possible pointer value: this keeps frame addresses
310 // increasing upward. Because we want to ensure that we don't accidentally change this, we have a C_ASSERT
311 // in stackwalk.cpp. Since it requires constant values as args, we need to define FRAME_TOP in two steps.
312 // First we define FRAME_TOP_VALUE which we'll use when we do the compile-time check, then we'll define
313 // FRAME_TOP in terms of FRAME_TOP_VALUE. Defining FRAME_TOP as a PTR_Frame means we don't have to type cast
314 // whenever we compare it to a PTR_Frame value (the usual use of the value).
315 #define FRAME_TOP_VALUE ~0 // we want to say -1 here, but gcc has trouble with the signed value
316 #define FRAME_TOP (PTR_Frame(FRAME_TOP_VALUE))
318 #ifndef DACCESS_COMPILE
320 #if defined(FEATURE_PAL) && !defined(CROSSGEN_COMPILE)
322 #define DEFINE_DTOR(klass) \
324 virtual ~klass() { PopIfChained(); }
328 #define DEFINE_DTOR(klass)
330 #endif // FEATURE_PAL && !CROSSGEN_COMPILE
332 #define DEFINE_VTABLE_GETTER(klass) \
334 static TADDR GetMethodFrameVPtr() { \
335 LIMITED_METHOD_CONTRACT; \
336 klass boilerplate(false); \
337 return *((TADDR*)&boilerplate); \
339 klass(bool dummy) { LIMITED_METHOD_CONTRACT; }
341 #define DEFINE_VTABLE_GETTER_AND_DTOR(klass) \
342 DEFINE_VTABLE_GETTER(klass) \
345 #define DEFINE_VTABLE_GETTER_AND_CTOR(klass) \
346 DEFINE_VTABLE_GETTER(klass) \
348 klass() { LIMITED_METHOD_CONTRACT; }
350 #define DEFINE_VTABLE_GETTER_AND_CTOR_AND_DTOR(klass) \
351 DEFINE_VTABLE_GETTER_AND_DTOR(klass) \
353 klass() { LIMITED_METHOD_CONTRACT; }
357 #define DEFINE_VTABLE_GETTER(klass) \
359 static TADDR GetMethodFrameVPtr() { \
360 LIMITED_METHOD_CONTRACT; \
361 return klass::VPtrTargetVTable(); \
364 #define DEFINE_VTABLE_GETTER_AND_DTOR(klass) \
365 DEFINE_VTABLE_GETTER(klass) \
367 #define DEFINE_VTABLE_GETTER_AND_CTOR(klass) \
368 DEFINE_VTABLE_GETTER(klass) \
370 #define DEFINE_VTABLE_GETTER_AND_CTOR_AND_DTOR(klass) \
371 DEFINE_VTABLE_GETTER_AND_CTOR(klass) \
373 #endif // #ifndef DACCESS_COMPILE
375 //-----------------------------------------------------------------------------
376 // For reporting on types of frames at runtime.
383 typedef DPTR(FrameTypeName) PTR_FrameTypeName;
385 //-----------------------------------------------------------------------------
386 // Frame depends on the location of its vtable within the object. This
387 // superclass ensures that the vtable for Frame objects is in the same
388 // location under both MSVC and GCC.
389 //-----------------------------------------------------------------------------
393 VPTR_BASE_VTABLE_CLASS(FrameBase)
396 FrameBase() {LIMITED_METHOD_CONTRACT; }
398 virtual void GcScanRoots(promote_func *fn, ScanContext* sc) {
399 LIMITED_METHOD_CONTRACT;
400 // Nothing to protect
403 #ifdef DACCESS_COMPILE
404 virtual void EnumMemoryRegions(CLRDataEnumMemoryFlags flags) = 0;
408 //------------------------------------------------------------------------
409 // Frame defines methods common to all frame types. There are no actual
410 // instances of root frames.
411 //------------------------------------------------------------------------
413 class Frame : public FrameBase
415 friend class CheckAsmOffsets;
416 #ifdef DACCESS_COMPILE
417 friend void Thread::EnumMemoryRegions(CLRDataEnumMemoryFlags flags);
420 VPTR_ABSTRACT_VTABLE_CLASS(Frame, FrameBase)
424 //------------------------------------------------------------------------
425 // Special characteristics of a frame
426 //------------------------------------------------------------------------
429 FRAME_ATTR_EXCEPTION = 1, // This frame caused an exception
430 FRAME_ATTR_OUT_OF_LINE = 2, // The exception out of line (IP of the frame is not correct)
431 FRAME_ATTR_FAULTED = 4, // Exception caused by Win32 fault
432 FRAME_ATTR_RESUMABLE = 8, // We may resume from this frame
433 FRAME_ATTR_CAPTURE_DEPTH_2 = 0x10, // This is a helperMethodFrame and the capture occurred at depth 2
434 FRAME_ATTR_EXACT_DEPTH = 0x20, // This is a helperMethodFrame and a jit helper, but only crawl to the given depth
435 FRAME_ATTR_NO_THREAD_ABORT = 0x40, // This is a helperMethodFrame that should not trigger thread aborts on entry
437 virtual unsigned GetFrameAttribs()
439 LIMITED_METHOD_DAC_CONTRACT;
440 return FRAME_ATTR_NONE;
443 //------------------------------------------------------------------------
444 // Performs cleanup on an exception unwind
445 //------------------------------------------------------------------------
446 #ifndef DACCESS_COMPILE
447 virtual void ExceptionUnwind()
449 // Nothing to do here.
450 LIMITED_METHOD_CONTRACT;
454 // Should be overridden to return TRUE if the frame contains register
455 // state of the caller.
456 virtual BOOL NeedsUpdateRegDisplay()
461 //------------------------------------------------------------------------
462 // Is this a frame used on transition to native code from jitted code?
463 //------------------------------------------------------------------------
464 virtual BOOL IsTransitionToNativeFrame()
466 LIMITED_METHOD_CONTRACT;
470 virtual MethodDesc *GetFunction()
472 LIMITED_METHOD_DAC_CONTRACT;
476 virtual Assembly *GetAssembly()
479 MethodDesc *pMethod = GetFunction();
481 return pMethod->GetModule()->GetAssembly();
486 // indicate the current X86 IP address within the current method
487 // return 0 if the information is not available
488 virtual PTR_BYTE GetIP()
490 LIMITED_METHOD_CONTRACT;
494 // DACCESS: GetReturnAddressPtr should return the
495 // target address of the return address in the frame.
496 virtual TADDR GetReturnAddressPtr()
498 LIMITED_METHOD_DAC_CONTRACT;
502 virtual PCODE GetReturnAddress()
505 TADDR ptr = GetReturnAddressPtr();
506 return (ptr != NULL) ? *PTR_PCODE(ptr) : NULL;
509 AppDomain *GetReturnDomain()
511 LIMITED_METHOD_CONTRACT;
515 #ifndef DACCESS_COMPILE
516 virtual Object **GetReturnExecutionContextAddr()
518 LIMITED_METHOD_CONTRACT;
522 void SetReturnAddress(TADDR val)
525 TADDR ptr = GetReturnAddressPtr();
526 _ASSERTE(ptr != NULL);
529 #endif // #ifndef DACCESS_COMPILE
531 PTR_GSCookie GetGSCookiePtr()
534 return dac_cast<PTR_GSCookie>(dac_cast<TADDR>(this) + GetOffsetOfGSCookie());
537 static int GetOffsetOfGSCookie()
539 LIMITED_METHOD_DAC_CONTRACT;
540 return -(int)sizeof(GSCookie);
543 static bool HasValidVTablePtr(Frame * pFrame);
544 static PTR_GSCookie SafeGetGSCookiePtr(Frame * pFrame);
547 // Callers, note that the REGDISPLAY parameter is actually in/out. While
548 // UpdateRegDisplay is generally used to fill out the REGDISPLAY parameter, some
549 // overrides (e.g., code:ResumableFrame::UpdateRegDisplay) will actually READ what
550 // you pass in. So be sure to pass in a valid or zeroed out REGDISPLAY.
551 virtual void UpdateRegDisplay(const PREGDISPLAY)
553 LIMITED_METHOD_DAC_CONTRACT;
557 //------------------------------------------------------------------------
559 //------------------------------------------------------------------------
566 TT_M2U, // we can safely cast to a FramedMethodFrame
567 TT_U2M, // we can safely cast to a UnmanagedToManagedFrame
568 TT_AppDomain, // transitioniting between AppDomains.
569 TT_InternalCall, // calling into the CLR (ecall/fcall).
572 // Get the type of transition.
574 virtual ETransitionType GetTransitionType()
576 LIMITED_METHOD_DAC_CONTRACT;
592 // HMFs and derived classes should use this so the profiling API knows it needs
593 // to ensure HMF-specific lazy initialization gets done w/out re-entering to the host.
594 TYPE_HELPER_METHOD_FRAME,
599 virtual int GetFrameType()
601 LIMITED_METHOD_DAC_CONTRACT;
602 return TYPE_INTERNAL;
605 // When stepping into a method, various other methods may be called.
606 // These are refererred to as interceptors. They are all invoked
607 // with frames of various types. GetInterception() indicates whether
608 // the frame was set up for execution of such interceptors
613 INTERCEPTION_CLASS_INIT,
614 INTERCEPTION_EXCEPTION,
615 INTERCEPTION_CONTEXT,
616 INTERCEPTION_SECURITY,
617 INTERCEPTION_PRESTUB,
623 virtual Interception GetInterception()
625 LIMITED_METHOD_DAC_CONTRACT;
626 return INTERCEPTION_NONE;
629 // Return information about an unmanaged call the frame
631 // ip - the unmanaged routine which will be called
632 // returnIP - the address in the stub which the unmanaged routine
634 // returnSP - the location returnIP is pushed onto the stack
637 virtual void GetUnmanagedCallSite(TADDR* ip,
641 LIMITED_METHOD_CONTRACT;
652 // Return where the frame will execute next - the result is filled
653 // into the given "trace" structure. The frame is responsible for
654 // detecting where it is in its execution lifetime.
655 virtual BOOL TraceFrame(Thread *thread, BOOL fromPatch,
656 TraceDestination *trace, REGDISPLAY *regs)
658 LIMITED_METHOD_CONTRACT;
659 LOG((LF_CORDB, LL_INFO10000,
660 "Default TraceFrame always returns false.\n"));
664 #ifdef DACCESS_COMPILE
665 virtual void EnumMemoryRegions(CLRDataEnumMemoryFlags flags)
670 // Many frames store a MethodDesc pointer in m_Datum
671 // so pick that up automatically.
672 MethodDesc* func = GetFunction();
675 func->EnumMemoryRegions(flags);
678 // Include the NegSpace
679 GSCookie * pGSCookie = GetGSCookiePtr();
680 _ASSERTE(FitsIn<ULONG32>(PBYTE(pGSCookie) - PBYTE(this)));
681 ULONG32 negSpaceSize = static_cast<ULONG32>(PBYTE(pGSCookie) - PBYTE(this));
682 DacEnumMemoryRegion(dac_cast<TADDR>(this) - negSpaceSize, negSpaceSize);
686 //---------------------------------------------------------------
687 // Expose key offsets and values for stub generation.
688 //---------------------------------------------------------------
689 static BYTE GetOffsetOfNextLink()
692 size_t ofs = offsetof(class Frame, m_Next);
693 _ASSERTE(FitsInI1(ofs));
697 // get your VTablePointer (can be used to check what type the frame is)
700 LIMITED_METHOD_DAC_CONTRACT;
701 return VPTR_HOST_VTABLE_TO_TADDR(*(LPVOID*)this);
704 #if defined(_DEBUG) && !defined(DACCESS_COMPILE)
705 virtual BOOL Protects(OBJECTREF *ppObjectRef)
707 LIMITED_METHOD_CONTRACT;
712 #ifndef DACCESS_COMPILE
713 // Link and Unlink this frame
716 VOID Push(Thread *pThread);
717 VOID Pop(Thread *pThread);
718 #endif // DACCESS_COMPILE
722 static BOOL ShouldLogTransitions() { WRAPPER_NO_CONTRACT; return LoggingOn(LF_STUBS, LL_INFO1000000); }
723 static void __stdcall LogTransition(Frame* frame);
724 void LogFrame(int LF, int LL); // General purpose logging.
725 void LogFrameChain(int LF, int LL); // Log the whole chain.
726 virtual const char* GetFrameTypeName() {return NULL;}
727 static PTR_CSTR GetFrameTypeName(TADDR vtbl);
730 //------------------------------------------------------------------------
731 // Returns the address of a security object or
732 // null if there is no space for an object on this frame.
733 //------------------------------------------------------------------------
734 virtual OBJECTREF *GetAddrOfSecurityDesc()
736 LIMITED_METHOD_CONTRACT;
741 // Pointer to the next frame up the stack.
744 PTR_Frame m_Next; // offset +4
747 PTR_Frame PtrNextFrame() { return m_Next; }
750 // Because JIT-method activations cannot be expressed as Frames,
751 // everyone must use the StackCrawler to walk the frame chain
752 // reliably. We'll expose the Next method only to the StackCrawler
753 // to prevent mistakes.
754 /*<TODO>@NICE: Restrict "friendship" again to the StackWalker method;
755 not done because of circular dependency with threads.h</TODO>
757 // friend Frame* Thread::StackWalkFrames(PSTACKWALKFRAMESCALLBACK pCallback, VOID *pData);
759 friend void CrawlFrame::GotoNextFrame();
760 friend class StackFrameIterator;
761 friend class TailCallFrame;
762 friend class AppDomain;
763 friend VOID RealCOMPlusThrow(OBJECTREF
764 #ifdef FEATURE_CORRUPTING_EXCEPTIONS
765 , CorruptionSeverity severity
766 #endif // FEATURE_CORRUPTING_EXCEPTIONS
768 friend FCDECL0(VOID, JIT_StressGC);
770 friend LONG WINAPI CLRVectoredExceptionHandlerShim(PEXCEPTION_POINTERS pExceptionInfo);
773 friend Thread * __stdcall JIT_InitPInvokeFrame(InlinedCallFrame *pFrame, PTR_VOID StubSecretArg);
775 #ifdef WIN64EXCEPTIONS
776 friend class ExceptionTracker;
778 #if defined(DACCESS_COMPILE)
779 friend class DacDbiInterfaceImpl;
780 #endif // DACCESS_COMPILE
784 LIMITED_METHOD_DAC_CONTRACT;
789 // Frame is considered an abstract class: this protected constructor
790 // causes any attempt to instantiate one to fail at compile-time.
792 : m_Next(dac_cast<PTR_Frame>(nullptr))
794 LIMITED_METHOD_CONTRACT;
797 #if defined(FEATURE_PAL) && !defined(DACCESS_COMPILE) && !defined(CROSSGEN_COMPILE)
798 virtual ~Frame() { LIMITED_METHOD_CONTRACT; }
801 #endif // FEATURE_PAL && !DACCESS_COMPILE && !CROSSGEN_COMPILE
805 //-----------------------------------------------------------------------------
806 // This frame provides context for a frame that
807 // took an exception that is going to be resumed.
809 // It is necessary to create this frame if garbage
810 // collection may happen during handling of the
811 // exception. The FRAME_ATTR_RESUMABLE flag tells
812 // the GC that the preceding frame needs to be treated
813 // like the top of stack (with the important implication that
814 // caller-save-regsiters will be potential roots).
815 //-----------------------------------------------------------------------------
816 #ifdef FEATURE_HIJACK
817 //-----------------------------------------------------------------------------
819 class ResumableFrame : public Frame
821 VPTR_VTABLE_CLASS(ResumableFrame, Frame)
824 #ifndef DACCESS_COMPILE
825 ResumableFrame(T_CONTEXT* regs) {
826 LIMITED_METHOD_CONTRACT;
831 virtual TADDR GetReturnAddressPtr();
833 virtual BOOL NeedsUpdateRegDisplay()
838 virtual void UpdateRegDisplay(const PREGDISPLAY pRD);
840 virtual unsigned GetFrameAttribs() {
841 LIMITED_METHOD_DAC_CONTRACT;
842 return FRAME_ATTR_RESUMABLE; // Treat the next frame as the top frame.
845 T_CONTEXT *GetContext() {
846 LIMITED_METHOD_DAC_CONTRACT;
850 #ifdef DACCESS_COMPILE
851 virtual void EnumMemoryRegions(CLRDataEnumMemoryFlags flags)
854 Frame::EnumMemoryRegions(flags);
862 // Keep as last entry in class
863 DEFINE_VTABLE_GETTER_AND_CTOR_AND_DTOR(ResumableFrame)
867 //-----------------------------------------------------------------------------
868 // RedirectedThreadFrame
869 //-----------------------------------------------------------------------------
871 class RedirectedThreadFrame : public ResumableFrame
873 VPTR_VTABLE_CLASS(RedirectedThreadFrame, ResumableFrame)
874 VPTR_UNIQUE(VPTR_UNIQUE_RedirectedThreadFrame)
877 #ifndef DACCESS_COMPILE
878 RedirectedThreadFrame(T_CONTEXT *regs) : ResumableFrame(regs) {
879 LIMITED_METHOD_CONTRACT;
882 virtual void ExceptionUnwind();
885 // Keep as last entry in class
886 DEFINE_VTABLE_GETTER_AND_CTOR_AND_DTOR(RedirectedThreadFrame)
889 typedef DPTR(RedirectedThreadFrame) PTR_RedirectedThreadFrame;
891 inline BOOL ISREDIRECTEDTHREAD(Thread * thread)
894 return (thread->GetFrame() != FRAME_TOP &&
895 thread->GetFrame()->GetVTablePtr() ==
896 RedirectedThreadFrame::GetMethodFrameVPtr());
899 inline T_CONTEXT * GETREDIRECTEDCONTEXT(Thread * thread)
902 _ASSERTE(ISREDIRECTEDTHREAD(thread));
903 return dac_cast<PTR_RedirectedThreadFrame>(thread->GetFrame())->GetContext();
906 //------------------------------------------------------------------------
907 #else // FEATURE_HIJACK
908 //------------------------------------------------------------------------
910 inline BOOL ISREDIRECTEDTHREAD(Thread * thread) { LIMITED_METHOD_CONTRACT; return FALSE; }
911 inline CONTEXT * GETREDIRECTEDCONTEXT(Thread * thread) { LIMITED_METHOD_CONTRACT; return (CONTEXT*) NULL; }
913 //------------------------------------------------------------------------
914 #endif // FEATURE_HIJACK
915 //------------------------------------------------------------------------
916 // This frame represents a transition from one or more nested frameless
917 // method calls to either a EE runtime helper function or a framed method.
918 // Because most stackwalks from the EE start with a full-fledged frame,
919 // anything but the most trivial call into the EE has to push this
920 // frame in order to prevent the frameless methods inbetween from
922 //------------------------------------------------------------------------
924 class TransitionFrame : public Frame
926 VPTR_ABSTRACT_VTABLE_CLASS(TransitionFrame, Frame)
929 virtual TADDR GetTransitionBlock() = 0;
931 // DACCESS: GetReturnAddressPtr should return the
932 // target address of the return address in the frame.
933 virtual TADDR GetReturnAddressPtr()
935 LIMITED_METHOD_DAC_CONTRACT;
936 return GetTransitionBlock() + TransitionBlock::GetOffsetOfReturnAddress();
939 //---------------------------------------------------------------
940 // Get the "this" object.
941 //---------------------------------------------------------------
945 Object* obj = PTR_Object(*PTR_TADDR(GetAddrOfThis()));
946 return ObjectToOBJECTREF(obj);
949 PTR_OBJECTREF GetThisPtr()
952 return PTR_OBJECTREF(GetAddrOfThis());
955 //---------------------------------------------------------------
956 // Get the extra info for shared generic code.
957 //---------------------------------------------------------------
958 PTR_VOID GetParamTypeArg();
960 //---------------------------------------------------------------
961 // Gets value indicating whether the generic parameter type
962 // argument should be supressed.
963 //---------------------------------------------------------------
964 virtual BOOL SuppressParamTypeArg()
969 protected: // we don't want people using this directly
970 //---------------------------------------------------------------
971 // Get the address of the "this" object. WARNING!!! Whether or not "this"
972 // is gc-protected is depends on the frame type!!!
973 //---------------------------------------------------------------
974 TADDR GetAddrOfThis();
977 //---------------------------------------------------------------
978 // For vararg calls, return cookie.
979 //---------------------------------------------------------------
980 VASigCookie *GetVASigCookie();
982 CalleeSavedRegisters *GetCalleeSavedRegisters()
984 LIMITED_METHOD_DAC_CONTRACT;
985 return dac_cast<PTR_CalleeSavedRegisters>(
986 GetTransitionBlock() + TransitionBlock::GetOffsetOfCalleeSavedRegisters());
989 ArgumentRegisters *GetArgumentRegisters()
991 LIMITED_METHOD_DAC_CONTRACT;
992 return dac_cast<PTR_ArgumentRegisters>(
993 GetTransitionBlock() + TransitionBlock::GetOffsetOfArgumentRegisters());
998 LIMITED_METHOD_DAC_CONTRACT;
999 return GetTransitionBlock() + sizeof(TransitionBlock);
1002 virtual BOOL NeedsUpdateRegDisplay()
1007 virtual void UpdateRegDisplay(const PREGDISPLAY);
1009 void UpdateRegDisplayHelper(const PREGDISPLAY, UINT cbStackPop);
1012 #if defined (_DEBUG) && !defined (DACCESS_COMPILE)
1013 virtual BOOL Protects(OBJECTREF *ppORef);
1014 #endif //defined (_DEBUG) && defined (DACCESS_COMPILE)
1016 // For use by classes deriving from FramedMethodFrame.
1017 void PromoteCallerStack(promote_func* fn, ScanContext* sc);
1019 void PromoteCallerStackHelper(promote_func* fn, ScanContext* sc,
1020 MethodDesc * pMD, MetaSig *pmsig);
1022 void PromoteCallerStackUsingGCRefMap(promote_func* fn, ScanContext* sc, PTR_BYTE pGCRefMap);
1025 UINT CbStackPopUsingGCRefMap(PTR_BYTE pGCRefMap);
1031 LIMITED_METHOD_CONTRACT;
1035 //-----------------------------------------------------------------------
1036 // TransitionFrames for exceptions
1037 //-----------------------------------------------------------------------
1039 // The define USE_FEF controls how this class is used. Look for occurances
1042 class FaultingExceptionFrame : public Frame
1044 friend class CheckAsmOffsets;
1046 #ifndef WIN64EXCEPTIONS
1049 CalleeSavedRegisters m_regs;
1050 TADDR m_ReturnAddress;
1051 #else // _TARGET_X86_
1052 #error "Unsupported architecture"
1053 #endif // _TARGET_X86_
1054 #else // WIN64EXCEPTIONS
1055 BOOL m_fFilterExecuted; // Flag for FirstCallToHandler
1056 TADDR m_ReturnAddress;
1058 #endif // !WIN64EXCEPTIONS
1060 VPTR_VTABLE_CLASS(FaultingExceptionFrame, Frame)
1063 #ifndef DACCESS_COMPILE
1064 FaultingExceptionFrame() {
1065 LIMITED_METHOD_CONTRACT;
1069 virtual TADDR GetReturnAddressPtr()
1071 LIMITED_METHOD_DAC_CONTRACT;
1072 return PTR_HOST_MEMBER_TADDR(FaultingExceptionFrame, this, m_ReturnAddress);
1075 void Init(T_CONTEXT *pContext);
1076 void InitAndLink(T_CONTEXT *pContext);
1078 Interception GetInterception()
1080 LIMITED_METHOD_DAC_CONTRACT;
1081 return INTERCEPTION_EXCEPTION;
1084 unsigned GetFrameAttribs()
1086 LIMITED_METHOD_DAC_CONTRACT;
1087 return FRAME_ATTR_EXCEPTION | FRAME_ATTR_FAULTED;
1090 #ifndef WIN64EXCEPTIONS
1091 CalleeSavedRegisters *GetCalleeSavedRegisters()
1094 LIMITED_METHOD_DAC_CONTRACT;
1097 PORTABILITY_ASSERT("GetCalleeSavedRegisters");
1098 #endif // _TARGET_X86_
1100 #endif // WIN64EXCEPTIONS
1102 #ifdef WIN64EXCEPTIONS
1103 T_CONTEXT *GetExceptionContext ()
1105 LIMITED_METHOD_CONTRACT;
1109 BOOL * GetFilterExecutedFlag()
1111 LIMITED_METHOD_CONTRACT;
1112 return &m_fFilterExecuted;
1114 #endif // WIN64EXCEPTIONS
1116 virtual BOOL NeedsUpdateRegDisplay()
1121 virtual void UpdateRegDisplay(const PREGDISPLAY);
1123 // Keep as last entry in class
1124 DEFINE_VTABLE_GETTER_AND_DTOR(FaultingExceptionFrame)
1127 //-----------------------------------------------------------------------
1128 // Frame for debugger function evaluation
1130 // This frame holds a ptr to a DebuggerEval object which contains a copy
1131 // of the thread's context at the time it was hijacked for the func
1134 // UpdateRegDisplay updates all registers inthe REGDISPLAY, not just
1135 // the callee saved registers, because we can hijack for a func eval
1136 // at any point in a thread's execution.
1138 //-----------------------------------------------------------------------
1140 #ifdef DEBUGGING_SUPPORTED
1142 typedef DPTR(class DebuggerEval) PTR_DebuggerEval;
1144 class FuncEvalFrame : public Frame
1146 VPTR_VTABLE_CLASS(FuncEvalFrame, Frame)
1148 TADDR m_ReturnAddress;
1149 PTR_DebuggerEval m_pDebuggerEval;
1154 #ifndef DACCESS_COMPILE
1155 FuncEvalFrame(DebuggerEval *pDebuggerEval, TADDR returnAddress, BOOL showFrame)
1157 LIMITED_METHOD_CONTRACT;
1158 m_pDebuggerEval = pDebuggerEval;
1159 m_ReturnAddress = returnAddress;
1160 m_showFrame = showFrame;
1164 virtual BOOL IsTransitionToNativeFrame()
1166 LIMITED_METHOD_CONTRACT;
1170 virtual int GetFrameType()
1172 LIMITED_METHOD_DAC_CONTRACT;
1173 return TYPE_FUNC_EVAL;
1176 virtual unsigned GetFrameAttribs();
1178 virtual BOOL NeedsUpdateRegDisplay()
1183 virtual void UpdateRegDisplay(const PREGDISPLAY);
1185 virtual DebuggerEval * GetDebuggerEval();
1187 virtual TADDR GetReturnAddressPtr();
1192 * Returns if this frame should be returned as part of a stack trace to a debugger or not.
1197 LIMITED_METHOD_CONTRACT;
1202 // Keep as last entry in class
1203 DEFINE_VTABLE_GETTER_AND_CTOR_AND_DTOR(FuncEvalFrame)
1206 typedef VPTR(FuncEvalFrame) PTR_FuncEvalFrame;
1207 #endif // DEBUGGING_SUPPORTED
1209 //----------------------------------------------------------------------------------------------
1210 // A HelperMethodFrame is created by jit helper (Modified slightly it could be used
1211 // for native routines). This frame just does the callee saved register fixup.
1212 // It does NOT protect arguments; you must use GCPROTECT or one of the HelperMethodFrame
1213 // subclases. (see JitInterface for sample use, YOU CAN'T RETURN WHILE IN THE PROTECTED STATE!)
1214 //----------------------------------------------------------------------------------------------
1216 class HelperMethodFrame : public Frame
1218 VPTR_VTABLE_CLASS(HelperMethodFrame, Frame);
1221 #ifndef DACCESS_COMPILE
1222 // Lazy initialization of HelperMethodFrame. Need to
1223 // call InsureInit to complete initialization
1224 // If this is an FCall, the first param is the entry point for the FCALL.
1225 // The MethodDesc will be looked up form this (lazily), and this method
1226 // will be used in stack reporting, if this is not an FCall pass a 0
1227 FORCEINLINE HelperMethodFrame(void* fCallFtnEntry, unsigned attribs = 0)
1229 WRAPPER_NO_CONTRACT;
1230 // Most of the initialization is actually done in HelperMethodFrame::Push()
1231 INDEBUG(memset(&m_Attribs, 0xCC, sizeof(HelperMethodFrame) - offsetof(HelperMethodFrame, m_Attribs));)
1232 m_Attribs = attribs;
1233 m_FCallEntry = (TADDR)fCallFtnEntry;
1235 #endif // DACCESS_COMPILE
1237 virtual int GetFrameType()
1239 LIMITED_METHOD_DAC_CONTRACT;
1240 return TYPE_HELPER_METHOD_FRAME;
1243 virtual PCODE GetReturnAddress()
1245 LIMITED_METHOD_DAC_CONTRACT;
1247 if (!m_MachState.isValid())
1249 #if defined(DACCESS_COMPILE)
1250 MachState unwoundState;
1251 InsureInit(false, &unwoundState);
1252 return unwoundState.GetRetAddr();
1253 #else // !DACCESS_COMPILE
1254 _ASSERTE(!"HMF's should always be initialized in the non-DAC world.");
1257 #endif // !DACCESS_COMPILE
1260 return m_MachState.GetRetAddr();
1263 virtual MethodDesc* GetFunction();
1265 virtual BOOL NeedsUpdateRegDisplay()
1270 virtual void UpdateRegDisplay(const PREGDISPLAY);
1272 virtual Interception GetInterception()
1274 WRAPPER_NO_CONTRACT;
1275 LIMITED_METHOD_DAC_CONTRACT;
1276 if (GetFrameAttribs() & FRAME_ATTR_EXCEPTION)
1277 return(INTERCEPTION_EXCEPTION);
1278 return(INTERCEPTION_NONE);
1281 virtual ETransitionType GetTransitionType()
1283 LIMITED_METHOD_DAC_CONTRACT;
1284 return TT_InternalCall;
1288 void SetAddrOfHaveCheckedRestoreState(BOOL* pDoneCheck)
1290 m_pDoneCheck = pDoneCheck;
1293 BOOL HaveDoneConfirmStateCheck()
1295 LIMITED_METHOD_CONTRACT;
1296 _ASSERTE(m_pDoneCheck != NULL);
1297 return *m_pDoneCheck;
1300 void SetHaveDoneConfirmStateCheck()
1302 LIMITED_METHOD_CONTRACT;
1303 _ASSERTE(m_pDoneCheck != NULL);
1304 *m_pDoneCheck = TRUE;
1308 virtual unsigned GetFrameAttribs()
1310 LIMITED_METHOD_DAC_CONTRACT;
1314 #ifdef DACCESS_COMPILE
1315 virtual void EnumMemoryRegions(CLRDataEnumMemoryFlags flags)
1317 WRAPPER_NO_CONTRACT;
1318 Frame::EnumMemoryRegions(flags);
1322 #ifndef DACCESS_COMPILE
1326 FORCEINLINE void Poll()
1328 WRAPPER_NO_CONTRACT;
1329 if (m_pThread->CatchAtSafePointOpportunistic())
1332 #endif // DACCESS_COMPILE
1334 BOOL InsureInit(bool initialInit, struct MachState* unwindState, HostCallPreference hostCallPreference = AllowHostCalls);
1336 LazyMachState * MachineState() {
1337 LIMITED_METHOD_CONTRACT;
1338 return &m_MachState;
1341 Thread * GetThread() {
1342 LIMITED_METHOD_CONTRACT;
1347 // Slow paths of Push/Pop are factored into a separate functions for better perf.
1348 NOINLINE void PushSlowHelper();
1349 NOINLINE void PopSlowHelper();
1352 PTR_MethodDesc m_pMD;
1354 INDEBUG(BOOL* m_pDoneCheck;)
1355 PTR_Thread m_pThread;
1356 TADDR m_FCallEntry; // used to determine our identity for stack traces
1358 LazyMachState m_MachState; // pRetAddr points to the return address and the stack arguments
1360 // Keep as last entry in class
1361 DEFINE_VTABLE_GETTER_AND_CTOR_AND_DTOR(HelperMethodFrame)
1364 // Restores registers saved in m_MachState
1365 EXTERN_C int __fastcall HelperMethodFrameRestoreState(
1366 INDEBUG_COMMA(HelperMethodFrame *pFrame)
1371 // workhorse for our promotion efforts
1372 inline void DoPromote(promote_func *fn, ScanContext* sc, OBJECTREF *address, BOOL interior)
1374 WRAPPER_NO_CONTRACT;
1376 // We use OBJECTREF_TO_UNCHECKED_OBJECTREF since address may be an interior pointer
1378 " Promoting pointer argument at" FMT_ADDR "from" FMT_ADDR "to ",
1379 DBG_ADDR(address), DBG_ADDR(OBJECTREF_TO_UNCHECKED_OBJECTREF(*address)) ));
1382 PromoteCarefully(fn, PTR_PTR_Object(address), sc);
1384 (*fn) (PTR_PTR_Object(address), sc, 0);
1386 LOG((LF_GC, INFO3, " " FMT_ADDR "\n", DBG_ADDR(OBJECTREF_TO_UNCHECKED_OBJECTREF(*address)) ));
1390 //-----------------------------------------------------------------------------
1391 // a HelplerMethodFrames that also report additional object references
1392 //-----------------------------------------------------------------------------
1394 class HelperMethodFrame_1OBJ : public HelperMethodFrame
1396 VPTR_VTABLE_CLASS(HelperMethodFrame_1OBJ, HelperMethodFrame)
1399 #if !defined(DACCESS_COMPILE) && !defined(CROSSGEN_COMPILE)
1400 HelperMethodFrame_1OBJ(void* fCallFtnEntry, unsigned attribs, OBJECTREF* aGCPtr1)
1401 : HelperMethodFrame(fCallFtnEntry, attribs)
1403 LIMITED_METHOD_CONTRACT;
1404 gcPtrs[0] = aGCPtr1;
1405 INDEBUG(Thread::ObjectRefProtected(aGCPtr1);)
1406 INDEBUG((*aGCPtr1).Validate ();)
1410 void SetProtectedObject(PTR_OBJECTREF objPtr)
1412 LIMITED_METHOD_CONTRACT;
1414 INDEBUG(Thread::ObjectRefProtected(objPtr);)
1417 virtual void GcScanRoots(promote_func *fn, ScanContext* sc)
1419 WRAPPER_NO_CONTRACT;
1420 DoPromote(fn, sc, gcPtrs[0], FALSE);
1421 HelperMethodFrame::GcScanRoots(fn, sc);
1425 #ifndef DACCESS_COMPILE
1428 WRAPPER_NO_CONTRACT;
1429 HelperMethodFrame::Pop();
1430 Thread::ObjectRefNew(gcPtrs[0]);
1432 #endif // DACCESS_COMPILE
1434 BOOL Protects(OBJECTREF *ppORef)
1436 LIMITED_METHOD_CONTRACT;
1437 return (ppORef == gcPtrs[0]) ? TRUE : FALSE;
1443 PTR_OBJECTREF gcPtrs[1];
1445 // Keep as last entry in class
1446 DEFINE_VTABLE_GETTER_AND_CTOR_AND_DTOR(HelperMethodFrame_1OBJ)
1450 //-----------------------------------------------------------------------------
1451 // HelperMethodFrame_2OBJ
1452 //-----------------------------------------------------------------------------
1454 class HelperMethodFrame_2OBJ : public HelperMethodFrame
1456 VPTR_VTABLE_CLASS(HelperMethodFrame_2OBJ, HelperMethodFrame)
1459 #if !defined(DACCESS_COMPILE) && !defined(CROSSGEN_COMPILE)
1460 HelperMethodFrame_2OBJ(
1461 void* fCallFtnEntry,
1465 : HelperMethodFrame(fCallFtnEntry, attribs)
1467 LIMITED_METHOD_CONTRACT;
1468 gcPtrs[0] = aGCPtr1;
1469 gcPtrs[1] = aGCPtr2;
1470 INDEBUG(Thread::ObjectRefProtected(aGCPtr1);)
1471 INDEBUG(Thread::ObjectRefProtected(aGCPtr2);)
1472 INDEBUG((*aGCPtr1).Validate ();)
1473 INDEBUG((*aGCPtr2).Validate ();)
1477 virtual void GcScanRoots(promote_func *fn, ScanContext* sc)
1479 WRAPPER_NO_CONTRACT;
1480 DoPromote(fn, sc, gcPtrs[0], FALSE);
1481 DoPromote(fn, sc, gcPtrs[1], FALSE);
1482 HelperMethodFrame::GcScanRoots(fn, sc);
1486 #ifndef DACCESS_COMPILE
1489 WRAPPER_NO_CONTRACT;
1490 HelperMethodFrame::Pop();
1491 Thread::ObjectRefNew(gcPtrs[0]);
1492 Thread::ObjectRefNew(gcPtrs[1]);
1494 #endif // DACCESS_COMPILE
1496 BOOL Protects(OBJECTREF *ppORef)
1498 LIMITED_METHOD_CONTRACT;
1499 return (ppORef == gcPtrs[0] || ppORef == gcPtrs[1]) ? TRUE : FALSE;
1504 PTR_OBJECTREF gcPtrs[2];
1506 // Keep as last entry in class
1507 DEFINE_VTABLE_GETTER_AND_CTOR_AND_DTOR(HelperMethodFrame_2OBJ)
1510 //-----------------------------------------------------------------------------
1511 // HelperMethodFrame_3OBJ
1512 //-----------------------------------------------------------------------------
1514 class HelperMethodFrame_3OBJ : public HelperMethodFrame
1516 VPTR_VTABLE_CLASS(HelperMethodFrame_3OBJ, HelperMethodFrame)
1519 #if !defined(DACCESS_COMPILE) && !defined(CROSSGEN_COMPILE)
1520 HelperMethodFrame_3OBJ(
1521 void* fCallFtnEntry,
1526 : HelperMethodFrame(fCallFtnEntry, attribs)
1528 LIMITED_METHOD_CONTRACT;
1529 gcPtrs[0] = aGCPtr1;
1530 gcPtrs[1] = aGCPtr2;
1531 gcPtrs[2] = aGCPtr3;
1532 INDEBUG(Thread::ObjectRefProtected(aGCPtr1);)
1533 INDEBUG(Thread::ObjectRefProtected(aGCPtr2);)
1534 INDEBUG(Thread::ObjectRefProtected(aGCPtr3);)
1535 INDEBUG((*aGCPtr1).Validate();)
1536 INDEBUG((*aGCPtr2).Validate();)
1537 INDEBUG((*aGCPtr3).Validate();)
1541 virtual void GcScanRoots(promote_func *fn, ScanContext* sc)
1543 WRAPPER_NO_CONTRACT;
1544 DoPromote(fn, sc, gcPtrs[0], FALSE);
1545 DoPromote(fn, sc, gcPtrs[1], FALSE);
1546 DoPromote(fn, sc, gcPtrs[2], FALSE);
1547 HelperMethodFrame::GcScanRoots(fn, sc);
1551 #ifndef DACCESS_COMPILE
1554 WRAPPER_NO_CONTRACT;
1555 HelperMethodFrame::Pop();
1556 Thread::ObjectRefNew(gcPtrs[0]);
1557 Thread::ObjectRefNew(gcPtrs[1]);
1558 Thread::ObjectRefNew(gcPtrs[2]);
1560 #endif // DACCESS_COMPILE
1562 BOOL Protects(OBJECTREF *ppORef)
1564 LIMITED_METHOD_CONTRACT;
1565 return (ppORef == gcPtrs[0] || ppORef == gcPtrs[1] || ppORef == gcPtrs[2]) ? TRUE : FALSE;
1570 PTR_OBJECTREF gcPtrs[3];
1572 // Keep as last entry in class
1573 DEFINE_VTABLE_GETTER_AND_CTOR_AND_DTOR(HelperMethodFrame_3OBJ)
1577 //-----------------------------------------------------------------------------
1578 // HelperMethodFrame_PROTECTOBJ
1579 //-----------------------------------------------------------------------------
1581 class HelperMethodFrame_PROTECTOBJ : public HelperMethodFrame
1583 VPTR_VTABLE_CLASS(HelperMethodFrame_PROTECTOBJ, HelperMethodFrame)
1586 #if !defined(DACCESS_COMPILE) && !defined(CROSSGEN_COMPILE)
1587 HelperMethodFrame_PROTECTOBJ(void* fCallFtnEntry, unsigned attribs, OBJECTREF* pObjRefs, int numObjRefs)
1588 : HelperMethodFrame(fCallFtnEntry, attribs)
1590 LIMITED_METHOD_CONTRACT;
1591 m_pObjRefs = pObjRefs;
1592 m_numObjRefs = numObjRefs;
1594 for (UINT i = 0; i < m_numObjRefs; i++) {
1595 Thread::ObjectRefProtected(&m_pObjRefs[i]);
1596 m_pObjRefs[i].Validate();
1602 virtual void GcScanRoots(promote_func *fn, ScanContext* sc)
1604 WRAPPER_NO_CONTRACT;
1605 for (UINT i = 0; i < m_numObjRefs; i++) {
1606 DoPromote(fn, sc, &m_pObjRefs[i], FALSE);
1608 HelperMethodFrame::GcScanRoots(fn, sc);
1612 #ifndef DACCESS_COMPILE
1615 WRAPPER_NO_CONTRACT;
1616 HelperMethodFrame::Pop();
1617 for (UINT i = 0; i < m_numObjRefs; i++) {
1618 Thread::ObjectRefNew(&m_pObjRefs[i]);
1621 #endif // DACCESS_COMPILE
1623 BOOL Protects(OBJECTREF *ppORef)
1625 LIMITED_METHOD_CONTRACT;
1626 for (UINT i = 0; i < m_numObjRefs; i++) {
1627 if (ppORef == &m_pObjRefs[i])
1635 PTR_OBJECTREF m_pObjRefs;
1638 // Keep as last entry in class
1639 DEFINE_VTABLE_GETTER_AND_CTOR_AND_DTOR(HelperMethodFrame_PROTECTOBJ)
1642 class FramedMethodFrame : public TransitionFrame
1644 VPTR_ABSTRACT_VTABLE_CLASS(FramedMethodFrame, TransitionFrame)
1646 TADDR m_pTransitionBlock;
1649 PTR_MethodDesc m_pMD;
1652 #ifndef DACCESS_COMPILE
1653 FramedMethodFrame(TransitionBlock * pTransitionBlock, MethodDesc * pMD)
1654 : m_pTransitionBlock(dac_cast<TADDR>(pTransitionBlock)), m_pMD(pMD)
1656 LIMITED_METHOD_CONTRACT;
1658 #endif // DACCESS_COMPILE
1660 virtual TADDR GetTransitionBlock()
1662 LIMITED_METHOD_DAC_CONTRACT;
1663 return m_pTransitionBlock;
1666 virtual MethodDesc *GetFunction()
1668 LIMITED_METHOD_DAC_CONTRACT;
1672 #ifndef DACCESS_COMPILE
1673 void SetFunction(MethodDesc *pMD)
1679 MODE_COOPERATIVE; // Frame MethodDesc should be always updated in cooperative mode to avoid racing with GC stackwalk
1687 virtual ETransitionType GetTransitionType()
1689 LIMITED_METHOD_DAC_CONTRACT;
1690 return TT_M2U; // we can safely cast to a FramedMethodFrame
1695 LIMITED_METHOD_DAC_CONTRACT;
1699 #ifdef COM_STUBS_SEPARATE_FP_LOCATIONS
1700 static int GetFPArgOffset(int iArg)
1702 #ifdef _TARGET_AMD64_
1703 // Floating point spill area is between return value and transition block for frames that need it
1704 // (code:TPMethodFrame and code:ComPlusMethodFrame)
1705 return -(4 * 0x10 /* floating point args */ + 0x8 /* alignment pad */ + TransitionBlock::GetNegSpaceSize()) + (iArg * 0x10);
1711 // GetReturnObjectPtr and GetReturnValuePtr are only valid on frames
1714 PTR_PTR_Object GetReturnObjectPtr()
1716 LIMITED_METHOD_DAC_CONTRACT;
1717 return PTR_PTR_Object(GetReturnValuePtr());
1720 // Get return value address
1721 PTR_VOID GetReturnValuePtr()
1723 LIMITED_METHOD_DAC_CONTRACT;
1724 #ifdef COM_STUBS_SEPARATE_FP_LOCATIONS
1725 TADDR p = GetTransitionBlock() + GetFPArgOffset(0);
1727 TADDR p = GetTransitionBlock() - TransitionBlock::GetNegSpaceSize();
1729 // Return value is right before the transition block (or floating point spill area on AMD64) for frames that need it
1730 // (code:TPMethodFrame and code:ComPlusMethodFrame)
1731 #ifdef ENREGISTERED_RETURNTYPE_MAXSIZE
1732 p -= ENREGISTERED_RETURNTYPE_MAXSIZE;
1734 p -= sizeof(ARG_SLOT);
1736 return dac_cast<PTR_VOID>(p);
1742 LIMITED_METHOD_CONTRACT;
1746 //+----------------------------------------------------------------------------
1748 // Class: TPMethodFrame private
1750 // Synopsis: This frame is pushed onto the stack for calls on transparent
1754 //+----------------------------------------------------------------------------
1756 //------------------------------------------------------------------------
1757 // This represents a call Delegate.Invoke for secure delegate
1758 // It's only used to gc-protect the arguments during the call.
1759 // Actually the only reason to have this frame is so a proper
1760 // Assembly can be reported
1761 //------------------------------------------------------------------------
1763 class SecureDelegateFrame : public TransitionFrame
1765 VPTR_VTABLE_CLASS(SecureDelegateFrame, TransitionFrame)
1767 PTR_MethodDesc m_pMD;
1768 TransitionBlock m_TransitionBlock;
1771 virtual MethodDesc* GetFunction()
1773 LIMITED_METHOD_CONTRACT;
1777 virtual TADDR GetTransitionBlock()
1779 LIMITED_METHOD_DAC_CONTRACT;
1780 return PTR_HOST_MEMBER_TADDR(SecureDelegateFrame, this,
1784 static BYTE GetOffsetOfDatum()
1786 LIMITED_METHOD_DAC_CONTRACT;
1787 return offsetof(SecureDelegateFrame, m_pMD);
1790 static int GetOffsetOfTransitionBlock()
1792 LIMITED_METHOD_DAC_CONTRACT;
1793 return offsetof(SecureDelegateFrame, m_TransitionBlock);
1796 virtual void GcScanRoots(promote_func *fn, ScanContext* sc)
1798 WRAPPER_NO_CONTRACT;
1799 TransitionFrame::GcScanRoots(fn, sc);
1800 PromoteCallerStack(fn, sc);
1803 virtual Assembly *GetAssembly();
1807 LIMITED_METHOD_DAC_CONTRACT;
1808 return TYPE_MULTICAST;
1811 // For the debugger:
1812 // Our base class, FramedMethodFrame, is a M2U transition;
1813 // but Delegate.Invoke isn't. So override and fix it here.
1814 // If we didn't do this, we'd see a Managed/Unmanaged transition in debugger's stack trace.
1815 virtual ETransitionType GetTransitionType()
1817 LIMITED_METHOD_DAC_CONTRACT;
1821 virtual BOOL TraceFrame(Thread *thread, BOOL fromPatch,
1822 TraceDestination *trace, REGDISPLAY *regs);
1824 // Keep as last entry in class
1825 DEFINE_VTABLE_GETTER_AND_CTOR_AND_DTOR(SecureDelegateFrame)
1829 //------------------------------------------------------------------------
1830 // This represents a call Multicast.Invoke. It's only used to gc-protect
1831 // the arguments during the iteration.
1832 //------------------------------------------------------------------------
1834 class MulticastFrame : public SecureDelegateFrame
1836 VPTR_VTABLE_CLASS(MulticastFrame, SecureDelegateFrame)
1840 virtual Assembly *GetAssembly()
1842 WRAPPER_NO_CONTRACT;
1843 return Frame::GetAssembly();
1848 LIMITED_METHOD_DAC_CONTRACT;
1849 return TYPE_MULTICAST;
1852 virtual BOOL TraceFrame(Thread *thread, BOOL fromPatch,
1853 TraceDestination *trace, REGDISPLAY *regs);
1855 // Keep as last entry in class
1856 DEFINE_VTABLE_GETTER_AND_CTOR_AND_DTOR(MulticastFrame)
1860 //-----------------------------------------------------------------------
1861 // Transition frame from unmanaged to managed
1862 //-----------------------------------------------------------------------
1864 class UnmanagedToManagedFrame : public Frame
1866 friend class CheckAsmOffsets;
1868 VPTR_ABSTRACT_VTABLE_CLASS_AND_CTOR(UnmanagedToManagedFrame, Frame)
1872 // DACCESS: GetReturnAddressPtr should return the
1873 // target address of the return address in the frame.
1874 virtual TADDR GetReturnAddressPtr()
1876 LIMITED_METHOD_DAC_CONTRACT;
1877 return PTR_HOST_MEMBER_TADDR(UnmanagedToManagedFrame, this,
1881 virtual PCODE GetReturnAddress();
1883 // Retrieves pointer to the lowest-addressed argument on
1884 // the stack. Depending on the calling convention, this
1885 // may or may not be the first argument.
1886 TADDR GetPointerToArguments()
1888 LIMITED_METHOD_DAC_CONTRACT;
1889 return dac_cast<TADDR>(this) + GetOffsetOfArgs();
1892 // Exposes an offset for stub generation.
1893 static BYTE GetOffsetOfArgs()
1895 LIMITED_METHOD_DAC_CONTRACT;
1896 #if defined(_TARGET_ARM_) || defined(_TARGET_ARM64_)
1897 size_t ofs = offsetof(UnmanagedToManagedFrame, m_argumentRegisters);
1899 size_t ofs = sizeof(UnmanagedToManagedFrame);
1901 _ASSERTE(FitsInI1(ofs));
1905 // depends on the sub frames to return approp. type here
1908 LIMITED_METHOD_DAC_CONTRACT;
1912 static int GetOffsetOfDatum()
1914 LIMITED_METHOD_CONTRACT;
1915 return offsetof(UnmanagedToManagedFrame, m_pvDatum);
1919 static int GetOffsetOfCalleeSavedRegisters()
1921 LIMITED_METHOD_CONTRACT;
1922 return offsetof(UnmanagedToManagedFrame, m_calleeSavedRegisters);
1928 LIMITED_METHOD_DAC_CONTRACT;
1932 //------------------------------------------------------------------------
1933 // For the debugger.
1934 //------------------------------------------------------------------------
1935 virtual ETransitionType GetTransitionType()
1937 LIMITED_METHOD_DAC_CONTRACT;
1941 //------------------------------------------------------------------------
1942 // Performs cleanup on an exception unwind
1943 //------------------------------------------------------------------------
1944 #ifndef DACCESS_COMPILE
1945 virtual void ExceptionUnwind();
1949 TADDR m_pvDatum; // type depends on the sub class
1951 #if defined(_TARGET_X86_)
1952 CalleeSavedRegisters m_calleeSavedRegisters;
1953 TADDR m_ReturnAddress;
1954 #elif defined(_TARGET_ARM_)
1955 TADDR m_R11; // R11 chain
1956 TADDR m_ReturnAddress;
1957 ArgumentRegisters m_argumentRegisters;
1958 #elif defined (_TARGET_ARM64_)
1960 TADDR m_ReturnAddress;
1961 TADDR m_x8; // ret buff arg
1962 ArgumentRegisters m_argumentRegisters;
1964 TADDR m_ReturnAddress; // return address into unmanaged code
1968 #ifdef FEATURE_COMINTEROP
1970 //------------------------------------------------------------------------
1971 // This frame represents a transition from COM to COM+
1972 //------------------------------------------------------------------------
1974 class ComMethodFrame : public UnmanagedToManagedFrame
1976 VPTR_VTABLE_CLASS(ComMethodFrame, UnmanagedToManagedFrame)
1977 VPTR_UNIQUE(VPTR_UNIQUE_ComMethodFrame)
1982 // Return the # of stack bytes pushed by the unmanaged caller.
1983 UINT GetNumCallerStackBytes();
1986 PTR_ComCallMethodDesc GetComCallMethodDesc()
1988 LIMITED_METHOD_CONTRACT;
1989 return dac_cast<PTR_ComCallMethodDesc>(m_pvDatum);
1992 #ifndef DACCESS_COMPILE
1993 static void DoSecondPassHandlerCleanup(Frame * pCurFrame);
1994 #endif // !DACCESS_COMPILE
1997 // Keep as last entry in class
1998 DEFINE_VTABLE_GETTER_AND_CTOR_AND_DTOR(ComMethodFrame)
2001 typedef DPTR(class ComMethodFrame) PTR_ComMethodFrame;
2003 //------------------------------------------------------------------------
2004 // This represents a generic call from CLR to COM
2005 //------------------------------------------------------------------------
2007 class ComPlusMethodFrame : public FramedMethodFrame
2009 VPTR_VTABLE_CLASS(ComPlusMethodFrame, FramedMethodFrame)
2012 ComPlusMethodFrame(TransitionBlock * pTransitionBlock, MethodDesc * pMethodDesc);
2014 virtual void GcScanRoots(promote_func *fn, ScanContext* sc);
2016 virtual BOOL IsTransitionToNativeFrame()
2018 LIMITED_METHOD_CONTRACT;
2024 LIMITED_METHOD_DAC_CONTRACT;
2028 void GetUnmanagedCallSite(TADDR* ip,
2032 BOOL TraceFrame(Thread *thread, BOOL fromPatch,
2033 TraceDestination *trace, REGDISPLAY *regs);
2035 // Keep as last entry in class
2036 DEFINE_VTABLE_GETTER_AND_CTOR_AND_DTOR(ComPlusMethodFrame)
2039 #endif // FEATURE_COMINTEROP
2041 //------------------------------------------------------------------------
2042 // This represents a call from a helper to GetILStubForCalli
2043 //------------------------------------------------------------------------
2045 class PInvokeCalliFrame : public FramedMethodFrame
2047 VPTR_VTABLE_CLASS(PInvokeCalliFrame, FramedMethodFrame)
2049 PTR_VASigCookie m_pVASigCookie;
2050 PCODE m_pUnmanagedTarget;
2053 PInvokeCalliFrame(TransitionBlock * pTransitionBlock, VASigCookie * pVASigCookie, PCODE pUnmanagedTarget);
2055 virtual void GcScanRoots(promote_func *fn, ScanContext* sc)
2057 WRAPPER_NO_CONTRACT;
2058 FramedMethodFrame::GcScanRoots(fn, sc);
2059 PromoteCallerStack(fn, sc);
2062 void PromoteCallerStack(promote_func* fn, ScanContext* sc);
2065 virtual MethodDesc *GetFunction()
2067 LIMITED_METHOD_DAC_CONTRACT;
2073 LIMITED_METHOD_DAC_CONTRACT;
2074 return TYPE_INTERCEPTION;
2077 PCODE GetPInvokeCalliTarget()
2079 LIMITED_METHOD_CONTRACT;
2080 return m_pUnmanagedTarget;
2083 PTR_VASigCookie GetVASigCookie()
2085 LIMITED_METHOD_CONTRACT;
2086 return m_pVASigCookie;
2090 virtual void UpdateRegDisplay(const PREGDISPLAY);
2091 #endif // _TARGET_X86_
2093 BOOL TraceFrame(Thread *thread, BOOL fromPatch,
2094 TraceDestination *trace, REGDISPLAY *regs)
2096 WRAPPER_NO_CONTRACT;
2098 trace->InitForUnmanaged(GetPInvokeCalliTarget());
2102 // Keep as last entry in class
2103 DEFINE_VTABLE_GETTER_AND_CTOR_AND_DTOR(PInvokeCalliFrame)
2106 // Some context-related forwards.
2107 #ifdef FEATURE_HIJACK
2108 //------------------------------------------------------------------------
2109 // This frame represents a hijacked return. If we crawl back through it,
2110 // it gets us back to where the return should have gone (and eventually will
2112 //------------------------------------------------------------------------
2113 class HijackFrame : public Frame
2115 VPTR_VTABLE_CLASS(HijackFrame, Frame)
2116 VPTR_UNIQUE(VPTR_UNIQUE_HijackFrame);
2119 // DACCESS: GetReturnAddressPtr should return the
2120 // target address of the return address in the frame.
2121 virtual TADDR GetReturnAddressPtr()
2123 LIMITED_METHOD_DAC_CONTRACT;
2124 return PTR_HOST_MEMBER_TADDR(HijackFrame, this,
2128 virtual BOOL NeedsUpdateRegDisplay()
2130 LIMITED_METHOD_CONTRACT;
2134 virtual void UpdateRegDisplay(const PREGDISPLAY);
2135 virtual void GcScanRoots(promote_func *fn, ScanContext* sc);
2137 // HijackFrames are created by trip functions. See OnHijackTripThread()
2138 // They are real C++ objects on the stack.
2139 // So, it's a public function -- but that doesn't mean you should make some.
2140 HijackFrame(LPVOID returnAddress, Thread *thread, HijackArgs *args);
2144 TADDR m_ReturnAddress;
2145 PTR_Thread m_Thread;
2146 DPTR(HijackArgs) m_Args;
2148 // Keep as last entry in class
2149 DEFINE_VTABLE_GETTER_AND_CTOR_AND_DTOR(HijackFrame)
2152 #endif // FEATURE_HIJACK
2154 //------------------------------------------------------------------------
2155 // This represents a call to a method prestub. Because the prestub
2156 // can do gc and throw exceptions while building the replacement
2157 // stub, we need this frame to keep things straight.
2158 //------------------------------------------------------------------------
2160 class PrestubMethodFrame : public FramedMethodFrame
2162 VPTR_VTABLE_CLASS(PrestubMethodFrame, FramedMethodFrame)
2165 PrestubMethodFrame(TransitionBlock * pTransitionBlock, MethodDesc * pMD);
2167 virtual void GcScanRoots(promote_func *fn, ScanContext* sc)
2169 WRAPPER_NO_CONTRACT;
2170 FramedMethodFrame::GcScanRoots(fn, sc);
2171 PromoteCallerStack(fn, sc);
2174 BOOL TraceFrame(Thread *thread, BOOL fromPatch,
2175 TraceDestination *trace, REGDISPLAY *regs);
2179 LIMITED_METHOD_DAC_CONTRACT;
2180 return TYPE_INTERCEPTION;
2183 // Our base class is a a M2U TransitionType; but we're not. So override and set us back to None.
2184 ETransitionType GetTransitionType()
2186 LIMITED_METHOD_DAC_CONTRACT;
2190 Interception GetInterception();
2192 // Keep as last entry in class
2193 DEFINE_VTABLE_GETTER_AND_CTOR_AND_DTOR(PrestubMethodFrame)
2196 //------------------------------------------------------------------------
2197 // This represents a call into the virtual call stub manager
2198 // Because the stub manager can do gc and throw exceptions while
2199 // building the resolve and dispatch stubs and needs to communicate
2200 // if we need to setup for a methodDesc call or do a direct call
2201 // we need this frame to keep things straight.
2202 //------------------------------------------------------------------------
2204 class StubDispatchFrame : public FramedMethodFrame
2206 VPTR_VTABLE_CLASS(StubDispatchFrame, FramedMethodFrame)
2208 // Representative MethodTable * and slot. They are used to
2209 // compute the MethodDesc* lazily
2210 PTR_MethodTable m_pRepresentativeMT;
2211 UINT32 m_representativeSlot;
2213 // Indirection cell and containing module. Used to compute pGCRefMap lazily.
2214 PTR_Module m_pZapModule;
2215 TADDR m_pIndirection;
2217 // Cached pointer to native ref data.
2218 PTR_BYTE m_pGCRefMap;
2221 StubDispatchFrame(TransitionBlock * pTransitionBlock);
2223 MethodDesc* GetFunction();
2225 // Returns this frame GC ref map if it has one
2226 PTR_BYTE GetGCRefMap();
2229 virtual void UpdateRegDisplay(const PREGDISPLAY pRD);
2230 virtual PCODE GetReturnAddress();
2231 #endif // _TARGET_X86_
2233 PCODE GetUnadjustedReturnAddress()
2235 LIMITED_METHOD_DAC_CONTRACT;
2236 return FramedMethodFrame::GetReturnAddress();
2239 virtual void GcScanRoots(promote_func *fn, ScanContext* sc);
2241 #ifndef DACCESS_COMPILE
2242 void SetRepresentativeSlot(MethodTable * pMT, UINT32 representativeSlot)
2244 LIMITED_METHOD_CONTRACT;
2246 m_pRepresentativeMT = pMT;
2247 m_representativeSlot = representativeSlot;
2250 void SetCallSite(Module * pZapModule, TADDR pIndirection)
2252 LIMITED_METHOD_CONTRACT;
2254 m_pZapModule = pZapModule;
2255 m_pIndirection = pIndirection;
2258 void SetForNullReferenceException()
2260 LIMITED_METHOD_CONTRACT;
2262 // Nothing to do. Everything is initialized in Init.
2266 BOOL TraceFrame(Thread *thread, BOOL fromPatch,
2267 TraceDestination *trace, REGDISPLAY *regs);
2271 LIMITED_METHOD_CONTRACT;
2275 Interception GetInterception();
2277 virtual BOOL SuppressParamTypeArg()
2280 // Shared default interface methods (i.e. virtual interface methods with an implementation) require
2281 // an instantiation argument. But if we're in the stub dispatch frame, we haven't actually resolved
2282 // the method yet (we could end up in class's override of this method, for example).
2284 // So we need to pretent that unresolved default interface methods are like any other interface
2285 // methods and don't have an instantiation argument.
2287 // See code:CEEInfo::getMethodSigInternal
2289 assert(GetFunction()->GetMethodTable()->IsInterface());
2294 friend class VirtualCallStubManager;
2296 // Keep as last entry in class
2297 DEFINE_VTABLE_GETTER_AND_CTOR_AND_DTOR(StubDispatchFrame)
2300 typedef VPTR(class StubDispatchFrame) PTR_StubDispatchFrame;
2303 //------------------------------------------------------------------------
2304 // This represents a call from an ExternalMethodThunk or a VirtualImportThunk
2305 // Because the resolving of the target address can do gc and/or
2306 // throw exceptions we need this frame to report the gc references.
2307 //------------------------------------------------------------------------
2309 class ExternalMethodFrame : public FramedMethodFrame
2311 VPTR_VTABLE_CLASS(ExternalMethodFrame, FramedMethodFrame)
2313 // Indirection and containing module. Used to compute pGCRefMap lazily.
2314 PTR_Module m_pZapModule;
2315 TADDR m_pIndirection;
2317 // Cached pointer to native ref data.
2318 PTR_BYTE m_pGCRefMap;
2321 ExternalMethodFrame(TransitionBlock * pTransitionBlock);
2323 virtual void GcScanRoots(promote_func *fn, ScanContext* sc);
2325 // Returns this frame GC ref map if it has one
2326 PTR_BYTE GetGCRefMap();
2328 #ifndef DACCESS_COMPILE
2329 void SetCallSite(Module * pZapModule, TADDR pIndirection)
2331 LIMITED_METHOD_CONTRACT;
2333 m_pZapModule = pZapModule;
2334 m_pIndirection = pIndirection;
2340 LIMITED_METHOD_CONTRACT;
2344 Interception GetInterception();
2347 virtual void UpdateRegDisplay(const PREGDISPLAY pRD);
2350 // Keep as last entry in class
2351 DEFINE_VTABLE_GETTER_AND_CTOR_AND_DTOR(ExternalMethodFrame)
2354 typedef VPTR(class ExternalMethodFrame) PTR_ExternalMethodFrame;
2356 #ifdef FEATURE_READYTORUN
2357 class DynamicHelperFrame : public FramedMethodFrame
2359 VPTR_VTABLE_CLASS(DynamicHelperFrame, FramedMethodFrame)
2361 int m_dynamicHelperFrameFlags;
2364 DynamicHelperFrame(TransitionBlock * pTransitionBlock, int dynamicHelperFrameFlags);
2366 virtual void GcScanRoots(promote_func *fn, ScanContext* sc);
2369 virtual void UpdateRegDisplay(const PREGDISPLAY pRD);
2372 virtual ETransitionType GetTransitionType()
2374 LIMITED_METHOD_DAC_CONTRACT;
2375 return TT_InternalCall;
2378 // Keep as last entry in class
2379 DEFINE_VTABLE_GETTER_AND_CTOR_AND_DTOR(DynamicHelperFrame)
2382 typedef VPTR(class DynamicHelperFrame) PTR_DynamicHelperFrame;
2383 #endif // FEATURE_READYTORUN
2385 //------------------------------------------------------------------------
2386 // This frame is used for instantiating stubs when the argument transform
2387 // is too complex to generate a tail-calling stub.
2388 //------------------------------------------------------------------------
2389 #if !defined(_TARGET_X86_)
2390 class StubHelperFrame : public TransitionFrame
2392 friend class CheckAsmOffsets;
2393 friend class StubLinkerCPU;
2395 VPTR_VTABLE_CLASS(StubHelperFrame, TransitionFrame)
2396 VPTR_UNIQUE(VPTR_UNIQUE_StubHelperFrame)
2398 TransitionBlock m_TransitionBlock;
2400 virtual TADDR GetTransitionBlock()
2402 LIMITED_METHOD_DAC_CONTRACT;
2403 return PTR_HOST_MEMBER_TADDR(StubHelperFrame, this,
2407 static int GetOffsetOfTransitionBlock()
2409 LIMITED_METHOD_DAC_CONTRACT;
2410 return offsetof(StubHelperFrame, m_TransitionBlock);
2414 // Keep as last entry in class
2415 DEFINE_VTABLE_GETTER_AND_CTOR_AND_DTOR(StubHelperFrame)
2417 #endif // _TARGET_X86_
2419 #ifdef FEATURE_COMINTEROP
2421 //------------------------------------------------------------------------
2422 // This represents a com to com+ call method prestub.
2423 // we need to catch exceptions etc. so this frame is not the same
2424 // as the prestub method frame
2425 // Note that in rare IJW cases, the immediate caller could be a managed method
2426 // which pinvoke-inlined a call to a COM interface, which happenned to be
2427 // implemented by a managed function via COM-interop.
2428 //------------------------------------------------------------------------
2429 class ComPrestubMethodFrame : public ComMethodFrame
2431 friend class CheckAsmOffsets;
2433 VPTR_VTABLE_CLASS(ComPrestubMethodFrame, ComMethodFrame)
2436 // Set the vptr and GSCookie
2441 LIMITED_METHOD_DAC_CONTRACT;
2442 return TYPE_INTERCEPTION;
2445 // ComPrestubMethodFrame should return the same interception type as
2446 // code:PrestubMethodFrame.GetInterception.
2447 virtual Interception GetInterception()
2449 LIMITED_METHOD_DAC_CONTRACT;
2450 return INTERCEPTION_PRESTUB;
2453 // Our base class is a a M2U TransitionType; but we're not. So override and set us back to None.
2454 virtual ETransitionType GetTransitionType()
2456 LIMITED_METHOD_DAC_CONTRACT;
2460 virtual void ExceptionUnwind()
2465 // Keep as last entry in class
2466 DEFINE_VTABLE_GETTER_AND_CTOR_AND_DTOR(ComPrestubMethodFrame)
2469 #endif // FEATURE_COMINTEROP
2472 //------------------------------------------------------------------------
2473 // This frame protects object references for the EE's convenience.
2474 // This frame type actually is created from C++.
2475 //------------------------------------------------------------------------
2476 class GCFrame : public Frame
2478 VPTR_VTABLE_CLASS(GCFrame, Frame)
2483 //--------------------------------------------------------------------
2484 // This constructor pushes a new GCFrame on the frame chain.
2485 //--------------------------------------------------------------------
2486 #ifndef DACCESS_COMPILE
2488 LIMITED_METHOD_CONTRACT;
2491 GCFrame(OBJECTREF *pObjRefs, UINT numObjRefs, BOOL maybeInterior);
2492 GCFrame(Thread *pThread, OBJECTREF *pObjRefs, UINT numObjRefs, BOOL maybeInterior);
2494 void Init(Thread *pThread, OBJECTREF *pObjRefs, UINT numObjRefs, BOOL maybeInterior);
2497 //--------------------------------------------------------------------
2498 // Pops the GCFrame and cancels the GC protection. Also
2499 // trashes the contents of pObjRef's in _DEBUG.
2500 //--------------------------------------------------------------------
2503 virtual void GcScanRoots(promote_func *fn, ScanContext* sc);
2506 virtual BOOL Protects(OBJECTREF *ppORef)
2508 LIMITED_METHOD_CONTRACT;
2509 for (UINT i = 0; i < m_numObjRefs; i++) {
2510 if (ppORef == m_pObjRefs + i) {
2518 #ifndef DACCESS_COMPILE
2519 void *operator new (size_t sz, void* p)
2521 LIMITED_METHOD_CONTRACT;
2526 #if defined(_DEBUG_IMPL)
2527 const char* GetFrameTypeName() { LIMITED_METHOD_CONTRACT; return "GCFrame"; }
2531 PTR_OBJECTREF m_pObjRefs;
2533 PTR_Thread m_pCurThread;
2534 BOOL m_MaybeInterior;
2536 // Keep as last entry in class
2537 DEFINE_VTABLE_GETTER_AND_DTOR(GCFrame)
2540 #ifdef FEATURE_INTERPRETER
2541 class InterpreterFrame: public Frame
2543 VPTR_VTABLE_CLASS(InterpreterFrame, Frame)
2545 class Interpreter* m_interp;
2549 #ifndef DACCESS_COMPILE
2550 InterpreterFrame(class Interpreter* interp);
2552 class Interpreter* GetInterpreter() { return m_interp; }
2555 virtual void GcScanRoots(promote_func *fn, ScanContext* sc);
2557 MethodDesc* GetFunction();
2560 DEFINE_VTABLE_GETTER_AND_DTOR(InterpreterFrame)
2564 typedef VPTR(class InterpreterFrame) PTR_InterpreterFrame;
2565 #endif // FEATURE_INTERPRETER
2568 //-----------------------------------------------------------------------------
2571 typedef DPTR(ByRefInfo) PTR_ByRefInfo;
2575 PTR_ByRefInfo pNext;
2578 TypeHandle typeHandle;
2582 //-----------------------------------------------------------------------------
2583 // ProtectByRefsFrame
2584 //-----------------------------------------------------------------------------
2586 class ProtectByRefsFrame : public Frame
2588 VPTR_VTABLE_CLASS(ProtectByRefsFrame, Frame)
2591 #ifndef DACCESS_COMPILE
2592 ProtectByRefsFrame(Thread *pThread, ByRefInfo *brInfo)
2595 WRAPPER_NO_CONTRACT;
2596 Frame::Push(pThread);
2600 virtual void GcScanRoots(promote_func *fn, ScanContext *sc);
2603 PTR_ByRefInfo m_brInfo;
2605 // Keep as last entry in class
2606 DEFINE_VTABLE_GETTER_AND_CTOR_AND_DTOR(ProtectByRefsFrame)
2610 //-----------------------------------------------------------------------------
2612 struct ValueClassInfo;
2613 typedef DPTR(struct ValueClassInfo) PTR_ValueClassInfo;
2615 struct ValueClassInfo
2617 PTR_ValueClassInfo pNext;
2618 PTR_MethodTable pMT;
2621 ValueClassInfo(PTR_VOID aData, PTR_MethodTable aMT, PTR_ValueClassInfo aNext)
2622 : pNext(aNext), pMT(aMT), pData(aData)
2627 //-----------------------------------------------------------------------------
2628 // ProtectValueClassFrame
2629 //-----------------------------------------------------------------------------
2632 class ProtectValueClassFrame : public Frame
2634 VPTR_VTABLE_CLASS(ProtectValueClassFrame, Frame)
2637 #ifndef DACCESS_COMPILE
2638 ProtectValueClassFrame()
2641 WRAPPER_NO_CONTRACT;
2645 ProtectValueClassFrame(Thread *pThread, ValueClassInfo *vcInfo)
2648 WRAPPER_NO_CONTRACT;
2649 Frame::Push(pThread);
2653 virtual void GcScanRoots(promote_func *fn, ScanContext *sc);
2655 ValueClassInfo ** GetValueClassInfoList()
2657 LIMITED_METHOD_CONTRACT;
2663 ValueClassInfo *m_pVCInfo;
2665 // Keep as last entry in class
2666 DEFINE_VTABLE_GETTER_AND_DTOR(ProtectValueClassFrame)
2671 BOOL IsProtectedByGCFrame(OBJECTREF *ppObjectRef);
2675 //------------------------------------------------------------------------
2676 // DebuggerClassInitMarkFrame is a small frame whose only purpose in
2677 // life is to mark for the debugger that "class initialization code" is
2678 // being run. It does nothing useful except return good values from
2679 // GetFrameType and GetInterception.
2680 //------------------------------------------------------------------------
2682 class DebuggerClassInitMarkFrame : public Frame
2684 VPTR_VTABLE_CLASS(DebuggerClassInitMarkFrame, Frame)
2688 #ifndef DACCESS_COMPILE
2689 DebuggerClassInitMarkFrame()
2691 WRAPPER_NO_CONTRACT;
2696 virtual int GetFrameType()
2698 LIMITED_METHOD_DAC_CONTRACT;
2699 return TYPE_INTERCEPTION;
2702 virtual Interception GetInterception()
2704 LIMITED_METHOD_DAC_CONTRACT;
2705 return INTERCEPTION_CLASS_INIT;
2708 // Keep as last entry in class
2709 DEFINE_VTABLE_GETTER_AND_DTOR(DebuggerClassInitMarkFrame)
2713 //------------------------------------------------------------------------
2714 // DebuggerSecurityCodeMarkFrame is a small frame whose only purpose in
2715 // life is to mark for the debugger that "security code" is
2716 // being run. It does nothing useful except return good values from
2717 // GetFrameType and GetInterception.
2718 //------------------------------------------------------------------------
2720 class DebuggerSecurityCodeMarkFrame : public Frame
2722 VPTR_VTABLE_CLASS(DebuggerSecurityCodeMarkFrame, Frame)
2725 #ifndef DACCESS_COMPILE
2726 DebuggerSecurityCodeMarkFrame()
2728 WRAPPER_NO_CONTRACT;
2733 virtual int GetFrameType()
2735 LIMITED_METHOD_DAC_CONTRACT;
2736 return TYPE_INTERCEPTION;
2739 virtual Interception GetInterception()
2741 LIMITED_METHOD_DAC_CONTRACT;
2742 return INTERCEPTION_SECURITY;
2745 // Keep as last entry in class
2746 DEFINE_VTABLE_GETTER_AND_DTOR(DebuggerSecurityCodeMarkFrame)
2749 //------------------------------------------------------------------------
2750 // DebuggerExitFrame is a small frame whose only purpose in
2751 // life is to mark for the debugger that there is an exit transiton on
2752 // the stack. This is special cased for the "break" IL instruction since
2753 // it is an fcall using a helper frame which returns TYPE_CALL instead of
2754 // an ecall (as in System.Diagnostics.Debugger.Break()) which returns
2755 // TYPE_EXIT. This just makes the two consistent for debugging services.
2756 //------------------------------------------------------------------------
2758 class DebuggerExitFrame : public Frame
2760 VPTR_VTABLE_CLASS(DebuggerExitFrame, Frame)
2763 #ifndef DACCESS_COMPILE
2766 WRAPPER_NO_CONTRACT;
2771 virtual int GetFrameType()
2773 LIMITED_METHOD_DAC_CONTRACT;
2777 // Return information about an unmanaged call the frame
2779 // ip - the unmanaged routine which will be called
2780 // returnIP - the address in the stub which the unmanaged routine
2782 // returnSP - the location returnIP is pushed onto the stack
2785 virtual void GetUnmanagedCallSite(TADDR* ip,
2789 LIMITED_METHOD_CONTRACT;
2800 // Keep as last entry in class
2801 DEFINE_VTABLE_GETTER_AND_DTOR(DebuggerExitFrame)
2804 //---------------------------------------------------------------------------------------
2806 // DebuggerU2MCatchHandlerFrame is a small frame whose only purpose in life is to mark for the debugger
2807 // that there is catch handler inside the runtime which may catch and swallow managed exceptions. The
2808 // debugger needs this frame to send a CatchHandlerFound (CHF) notification. Without this frame, the
2809 // debugger doesn't know where a managed exception is caught.
2812 // Currently this frame is only used in code:DispatchInfo.InvokeMember, which is an U2M transition.
2815 class DebuggerU2MCatchHandlerFrame : public Frame
2817 VPTR_VTABLE_CLASS(DebuggerU2MCatchHandlerFrame, Frame)
2820 #ifndef DACCESS_COMPILE
2821 DebuggerU2MCatchHandlerFrame()
2823 WRAPPER_NO_CONTRACT;
2827 DebuggerU2MCatchHandlerFrame(Thread * pThread)
2829 WRAPPER_NO_CONTRACT;
2830 Frame::Push(pThread);
2834 ETransitionType GetTransitionType()
2836 LIMITED_METHOD_DAC_CONTRACT;
2840 // Keep as last entry in class
2841 DEFINE_VTABLE_GETTER_AND_DTOR(DebuggerU2MCatchHandlerFrame)
2845 class UMThunkMarshInfo;
2846 typedef DPTR(class UMThunkMarshInfo) PTR_UMThunkMarshInfo;
2849 typedef DPTR(class UMEntryThunk) PTR_UMEntryThunk;
2851 #if defined(_TARGET_X86_)
2852 //------------------------------------------------------------------------
2853 // This frame guards an unmanaged->managed transition thru a UMThk
2854 //------------------------------------------------------------------------
2856 class UMThkCallFrame : public UnmanagedToManagedFrame
2858 VPTR_VTABLE_CLASS(UMThkCallFrame, UnmanagedToManagedFrame)
2862 #ifdef DACCESS_COMPILE
2863 virtual void EnumMemoryRegions(CLRDataEnumMemoryFlags flags);
2866 PTR_UMEntryThunk GetUMEntryThunk();
2868 static int GetOffsetOfUMEntryThunk()
2870 WRAPPER_NO_CONTRACT;
2871 return GetOffsetOfDatum();
2876 // Keep as last entry in class
2877 DEFINE_VTABLE_GETTER_AND_CTOR_AND_DTOR(UMThkCallFrame)
2879 #endif // _TARGET_X86_ && !FEATURE_PAL
2881 #if defined(_TARGET_X86_) && defined(FEATURE_COMINTEROP)
2882 //-------------------------------------------------------------------------
2883 // Exception handler for COM to managed frame
2884 // and the layout of the exception registration record structure in the stack
2885 // the layout is similar to the NT's EXCEPTIONREGISTRATION record
2886 // followed by the UnmanagedToManagedFrame specific info
2888 struct ComToManagedExRecord
2890 EXCEPTION_REGISTRATION_RECORD m_ExReg;
2891 ArgumentRegisters m_argRegs;
2892 GSCookie m_gsCookie;
2893 UMThkCallFrame m_frame;
2895 UnmanagedToManagedFrame * GetCurrFrame()
2897 LIMITED_METHOD_CONTRACT;
2901 #endif // _TARGET_X86_ && FEATURE_COMINTEROP
2904 //------------------------------------------------------------------------
2905 // This frame is pushed by any JIT'ted method that contains one or more
2906 // inlined N/Direct calls. Note that the JIT'ted method keeps it pushed
2907 // the whole time to amortize the pushing cost across the entire method.
2908 //------------------------------------------------------------------------
2910 typedef DPTR(class InlinedCallFrame) PTR_InlinedCallFrame;
2912 class InlinedCallFrame : public Frame
2914 VPTR_VTABLE_CLASS(InlinedCallFrame, Frame)
2917 virtual MethodDesc *GetFunction()
2919 WRAPPER_NO_CONTRACT;
2920 if (FrameHasActiveCall(this) && HasFunction())
2921 return PTR_MethodDesc(m_Datum);
2928 WRAPPER_NO_CONTRACT;
2931 // See code:GenericPInvokeCalliHelper
2932 return ((m_Datum != NULL) && !(dac_cast<TADDR>(m_Datum) & 0x1));
2934 return ((dac_cast<TADDR>(m_Datum) & ~0xffff) != 0);
2938 // Retrieves the return address into the code that called out
2940 virtual TADDR GetReturnAddressPtr()
2942 WRAPPER_NO_CONTRACT;
2944 if (FrameHasActiveCall(this))
2945 return PTR_HOST_MEMBER_TADDR(InlinedCallFrame, this,
2946 m_pCallerReturnAddress);
2951 virtual BOOL NeedsUpdateRegDisplay()
2953 WRAPPER_NO_CONTRACT;
2954 return FrameHasActiveCall(this);
2957 // Given a methodDesc representing an ILStub for a pinvoke call,
2958 // this method will return the MethodDesc for the actual interop
2959 // method if the current InlinedCallFrame is inactive.
2960 PTR_MethodDesc GetActualInteropMethodDesc()
2962 #if defined(_TARGET_X86_) || defined(_TARGET_ARM_)
2963 // Important: This code relies on the way JIT lays out frames. Keep it in sync
2964 // with code:Compiler.lvaAssignFrameOffsets.
2967 // +--------------------+
2968 // | lvaStubArgumentVar | <= filled with EAX in prolog |
2969 // +--------------------+ |
2971 // | InlinedCallFrame | |
2972 // | | <= m_pCrawl.pFrame | to lower addresses
2973 // +--------------------+ V
2976 // Extract the actual MethodDesc to report from the InlinedCallFrame.
2977 TADDR addr = dac_cast<TADDR>(this) + sizeof(InlinedCallFrame);
2978 return PTR_MethodDesc(*PTR_TADDR(addr));
2979 #elif defined(_WIN64)
2980 // On 64bit, the actual interop MethodDesc is saved off in a field off the InlinedCrawlFrame
2981 // which is populated by the JIT. Refer to JIT_InitPInvokeFrame for details.
2982 return PTR_MethodDesc(m_StubSecretArg);
2984 _ASSERTE(!"NYI - Interop method reporting for this architecture!");
2986 #endif // defined(_TARGET_X86_) || defined(_TARGET_ARM_)
2989 virtual void UpdateRegDisplay(const PREGDISPLAY);
2991 // m_Datum contains MethodDesc ptr or
2992 // - on AMD64: CALLI target address (if lowest bit is set)
2993 // - on X86: argument stack size (if value is <64k)
2994 // See code:HasFunction.
2995 PTR_NDirectMethodDesc m_Datum;
2998 // IL stubs fill this field with the incoming secret argument when they erect
2999 // InlinedCallFrame so we know which interop method was invoked even if the frame
3000 // is not active at the moment.
3001 PTR_VOID m_StubSecretArg;
3004 // X86: ESP after pushing the outgoing arguments, and just before calling
3005 // out to unmanaged code.
3006 // Other platforms: the field stays set throughout the declaring method.
3007 PTR_VOID m_pCallSiteSP;
3009 // EIP where the unmanaged call will return to. This will be a pointer into
3010 // the code of the managed frame which has the InlinedCallFrame
3011 // This is set to NULL in the method prolog. It gets set just before the
3012 // call to the target and reset back to NULL after the stop-for-GC check
3013 // following the call.
3014 TADDR m_pCallerReturnAddress;
3016 // This is used only for EBP. Hence, a stackwalk will miss the other
3017 // callee-saved registers for the method with the InlinedCallFrame.
3018 // To prevent GC-holes, we do not keep any GC references in callee-saved
3019 // registers across an NDirect call.
3020 TADDR m_pCalleeSavedFP;
3022 // This field is used to cache the current thread object where this frame is
3023 // executing. This is especially helpful on Unix platforms for the PInvoke assembly
3024 // stubs, since there is no easy way to inline an implementation of GetThread.
3028 // Store the value of SP after prolog to ensure we can unwind functions that use
3029 // stackalloc. In these functions, the m_pCallSiteSP can already be augmented by
3030 // the stackalloc size, which is variable.
3031 TADDR m_pSPAfterProlog;
3032 #endif // _TARGET_ARM_
3035 //---------------------------------------------------------------
3036 // Expose key offsets and values for stub generation.
3037 //---------------------------------------------------------------
3039 static void GetEEInfo(CORINFO_EE_INFO::InlinedCallFrameInfo * pEEInfo);
3041 // Is the specified frame an InlinedCallFrame which has an active call
3042 // inside it right now?
3043 static BOOL FrameHasActiveCall(Frame *pFrame)
3045 WRAPPER_NO_CONTRACT;
3048 pFrame != FRAME_TOP &&
3049 InlinedCallFrame::GetMethodFrameVPtr() == pFrame->GetVTablePtr() &&
3050 dac_cast<TADDR>(dac_cast<PTR_InlinedCallFrame>(pFrame)->m_pCallerReturnAddress) != NULL;
3053 // Marks the frame as inactive.
3056 m_pCallerReturnAddress = NULL;
3061 LIMITED_METHOD_DAC_CONTRACT;
3065 virtual BOOL IsTransitionToNativeFrame()
3067 LIMITED_METHOD_CONTRACT;
3071 PTR_VOID GetCallSiteSP()
3073 LIMITED_METHOD_CONTRACT;
3074 return m_pCallSiteSP;
3077 TADDR GetCalleeSavedFP()
3079 LIMITED_METHOD_DAC_CONTRACT;
3080 return m_pCalleeSavedFP;
3083 // Set the vptr and GSCookie
3086 // Keep as last entry in class
3087 DEFINE_VTABLE_GETTER_AND_CTOR_AND_DTOR(InlinedCallFrame)
3090 //------------------------------------------------------------------------
3091 // This frame is used to mark a Context/AppDomain Transition
3092 //------------------------------------------------------------------------
3094 class ContextTransitionFrame : public Frame
3097 PTR_Object m_LastThrownObjectInParentContext;
3098 ULONG_PTR m_LockCount; // Number of locks the thread takes
3099 // before the transition.
3100 VPTR_VTABLE_CLASS(ContextTransitionFrame, Frame)
3103 virtual void GcScanRoots(promote_func *fn, ScanContext* sc);
3105 OBJECTREF GetLastThrownObjectInParentContext()
3107 return ObjectToOBJECTREF(m_LastThrownObjectInParentContext);
3110 void SetLastThrownObjectInParentContext(OBJECTREF lastThrownObject)
3112 m_LastThrownObjectInParentContext = OBJECTREFToObject(lastThrownObject);
3115 void SetLockCount(DWORD lockCount)
3117 LIMITED_METHOD_CONTRACT;
3118 m_LockCount = lockCount;
3120 DWORD GetLockCount()
3122 LIMITED_METHOD_CONTRACT;
3123 return (DWORD) m_LockCount;
3127 // Let debugger know that we're transitioning between AppDomains.
3128 ETransitionType GetTransitionType()
3130 LIMITED_METHOD_DAC_CONTRACT;
3131 return TT_AppDomain;
3134 #ifndef DACCESS_COMPILE
3135 ContextTransitionFrame()
3136 : m_LastThrownObjectInParentContext(NULL)
3139 LIMITED_METHOD_CONTRACT;
3143 // Keep as last entry in class
3144 DEFINE_VTABLE_GETTER_AND_DTOR(ContextTransitionFrame)
3147 // TODO [DAVBR]: For the full fix for VsWhidbey 450273, this
3148 // may be uncommented once isLegalManagedCodeCaller works properly
3149 // with non-return address inputs, and with non-DEBUG builds
3150 //bool isLegalManagedCodeCaller(TADDR retAddr);
3151 bool isRetAddr(TADDR retAddr, TADDR* whereCalled);
3153 //------------------------------------------------------------------------
3155 // This frame is used as padding for virtual stub dispatch tailcalls.
3156 // When A calls B via virtual stub dispatch, the stub dispatch stub resolves
3157 // the target code for B and jumps to it. If A wants to do a tail call,
3158 // it does not get a chance to unwind its frame since the virtual stub dispatch
3159 // stub is not set up to return the address of the target code (rather
3160 // than just jumping to it).
3161 // To do a tail call, A calls JIT_TailCall, which unwinds A's frame
3162 // and sets up a TailCallFrame. It then calls the stub dispatch stub
3163 // which disassembles the caller (JIT_TailCall, in this case) to get some information,
3164 // resolves the target code for B, and then jumps to B.
3165 // If B also does a virtual stub dispatch tail call, then we reuse the
3166 // existing TailCallFrame instead of setting up a second one.
3168 // We could eliminate TailCallFrame if we factor the VSD stub to return
3169 // the target code address. This is currently not a very important scenario
3170 // as tail calls on interface calls are uncommon.
3172 // This frame is used as padding for tailcalls which require more space
3173 // than the caller has in it's incoming argument space.
3174 // To do a tail call from A to B, A calls JIT_TailCall, which unwinds A's frame
3175 // and sets up a TailCallFrame and the arguments. It then jumps to B.
3176 // If B also does a tail call, then we reuse the
3177 // existing TailCallFrame instead of setting up a second one.
3179 // This is also used whenever value types that aren't enregisterable are
3180 // passed by value instead of ref. This is currently not a very important
3181 // scenario as tail calls are uncommon.
3183 //------------------------------------------------------------------------
3185 class TailCallFrame : public Frame
3187 VPTR_VTABLE_CLASS(TailCallFrame, Frame)
3189 #if defined(_TARGET_X86_)
3190 TADDR m_CallerAddress; // the address the tailcall was initiated from
3191 CalleeSavedRegisters m_regs; // callee saved registers - the stack walk assumes that all non-JIT frames have them
3192 TADDR m_ReturnAddress; // the return address of the tailcall
3193 #elif defined(_TARGET_AMD64_)
3195 TADDR m_padding; // code:StubLinkerCPU::CreateTailCallCopyArgsThunk expects the size of TailCallFrame to be 16-byte aligned
3196 CalleeSavedRegisters m_calleeSavedRegisters;
3197 TADDR m_ReturnAddress;
3198 #elif defined(_TARGET_ARM_)
3200 CalleeSavedRegisters m_calleeSavedRegisters;
3201 // alias saved link register as m_ReturnAddress
3203 INT32 r4, r5, r6, r7, r8, r9, r10;
3205 TADDR m_ReturnAddress;
3209 TADDR m_ReturnAddress;
3213 #ifndef CROSSGEN_COMPILE
3214 #if !defined(_TARGET_X86_)
3216 #ifndef DACCESS_COMPILE
3217 TailCallFrame(T_CONTEXT * pContext, Thread * pThread)
3219 InitFromContext(pContext);
3220 m_Next = pThread->GetFrame();
3223 void InitFromContext(T_CONTEXT * pContext);
3225 // Architecture-specific method to initialize a CONTEXT record as if the first
3226 // part of the TailCallHelperStub had executed
3227 static TailCallFrame * AdjustContextForTailCallHelperStub(_CONTEXT * pContext, size_t cbNewArgArea, Thread * pThread);
3230 static TailCallFrame * GetFrameFromContext(CONTEXT * pContext);
3231 #endif // !_TARGET_X86_
3233 #if defined(_TARGET_X86_)
3234 static TailCallFrame* FindTailCallFrame(Frame* pFrame)
3236 LIMITED_METHOD_CONTRACT;
3237 // loop through the frame chain
3238 while (pFrame->GetVTablePtr() != TailCallFrame::GetMethodFrameVPtr())
3239 pFrame = pFrame->m_Next;
3240 return (TailCallFrame*)pFrame;
3243 TADDR GetCallerAddress()
3245 LIMITED_METHOD_CONTRACT;
3246 return m_CallerAddress;
3248 #endif // _TARGET_X86_
3250 virtual TADDR GetReturnAddressPtr()
3252 LIMITED_METHOD_DAC_CONTRACT;
3253 return PTR_HOST_MEMBER_TADDR(TailCallFrame, this,
3257 virtual BOOL NeedsUpdateRegDisplay()
3262 virtual void UpdateRegDisplay(const PREGDISPLAY pRD);
3263 #endif // !CROSSGEN_COMPILE
3264 #ifdef _TARGET_AMD64_
3265 void SetGCLayout(TADDR pGCLayout)
3267 LIMITED_METHOD_CONTRACT;
3268 m_pGCLayout = pGCLayout;
3271 virtual void GcScanRoots(promote_func *fn, ScanContext* sc);
3273 void SetGCLayout(TADDR pGCLayout)
3275 LIMITED_METHOD_CONTRACT;
3276 _ASSERTE(pGCLayout == NULL);
3281 // Keep as last entry in class
3282 DEFINE_VTABLE_GETTER_AND_CTOR_AND_DTOR(TailCallFrame)
3285 //------------------------------------------------------------------------
3286 // ExceptionFilterFrame is a small frame whose only purpose in
3287 // life is to set SHADOW_SP_FILTER_DONE during unwind from exception filter.
3288 //------------------------------------------------------------------------
3290 class ExceptionFilterFrame : public Frame
3292 VPTR_VTABLE_CLASS(ExceptionFilterFrame, Frame)
3293 size_t* m_pShadowSP;
3296 #ifndef DACCESS_COMPILE
3297 ExceptionFilterFrame(size_t* pShadowSP)
3299 WRAPPER_NO_CONTRACT;
3300 m_pShadowSP = pShadowSP;
3306 // Nothing to do here.
3307 WRAPPER_NO_CONTRACT;
3312 void SetFilterDone()
3314 LIMITED_METHOD_CONTRACT;
3316 // Mark the filter as having completed
3319 // Make sure that CallJitEHFilterHelper marked us as being in the filter.
3320 _ASSERTE(*m_pShadowSP & ICodeManager::SHADOW_SP_IN_FILTER);
3321 *m_pShadowSP |= ICodeManager::SHADOW_SP_FILTER_DONE;
3327 // Keep as last entry in class
3328 DEFINE_VTABLE_GETTER_AND_CTOR_AND_DTOR(ExceptionFilterFrame)
3332 // We use IsProtectedByGCFrame to check if some OBJECTREF pointers are protected
3333 // against GC. That function doesn't know if a byref is from managed stack thus
3334 // protected by JIT. AssumeByrefFromJITStack is used to bypass that check if an
3335 // OBJECTRef pointer is passed from managed code to an FCall and it's in stack.
3336 class AssumeByrefFromJITStack : public Frame
3338 VPTR_VTABLE_CLASS(AssumeByrefFromJITStack, Frame)
3340 #ifndef DACCESS_COMPILE
3341 AssumeByrefFromJITStack(OBJECTREF *pObjRef)
3343 m_pObjRef = pObjRef;
3347 BOOL Protects(OBJECTREF *ppORef)
3349 LIMITED_METHOD_CONTRACT;
3350 return ppORef == m_pObjRef;
3354 OBJECTREF *m_pObjRef;
3356 // Keep as last entry in class
3357 DEFINE_VTABLE_GETTER_AND_DTOR(AssumeByrefFromJITStack)
3358 }; //AssumeByrefFromJITStack
3362 //-----------------------------------------------------------------------------
3363 // FrameWithCookie is used to declare a Frame in source code with a cookie
3364 // immediately preceeding it.
3365 // This is just a specialized version of GSCookieFor<T>
3367 // For Frames that are set up by stubs, the stub is responsible for setting up
3370 // Note that we have to play all these games for the GSCookie as the GSCookie
3371 // needs to precede the vtable pointer, so that the GSCookie is guaranteed to
3372 // catch any stack-buffer-overrun corruptions that overwrite the Frame data.
3374 //-----------------------------------------------------------------------------
3378 class GCSafeCollection;
3380 template <typename FrameType>
3381 class FrameWithCookie
3385 GSCookie m_gsCookie;
3391 // Overload all the required constructors
3395 m_gsCookie(GetProcessGSCookie()), m_frame() { WRAPPER_NO_CONTRACT; }
3397 FrameWithCookie(Thread * pThread) :
3398 m_gsCookie(GetProcessGSCookie()), m_frame(pThread) { WRAPPER_NO_CONTRACT; }
3400 FrameWithCookie(T_CONTEXT * pContext) :
3401 m_gsCookie(GetProcessGSCookie()), m_frame(pContext) { WRAPPER_NO_CONTRACT; }
3403 FrameWithCookie(TransitionBlock * pTransitionBlock) :
3404 m_gsCookie(GetProcessGSCookie()), m_frame(pTransitionBlock) { WRAPPER_NO_CONTRACT; }
3406 FrameWithCookie(TransitionBlock * pTransitionBlock, MethodDesc * pMD) :
3407 m_gsCookie(GetProcessGSCookie()), m_frame(pTransitionBlock, pMD) { WRAPPER_NO_CONTRACT; }
3409 FrameWithCookie(TransitionBlock * pTransitionBlock, VASigCookie * pVASigCookie, PCODE pUnmanagedTarget) :
3410 m_gsCookie(GetProcessGSCookie()), m_frame(pTransitionBlock, pVASigCookie, pUnmanagedTarget) { WRAPPER_NO_CONTRACT; }
3412 FrameWithCookie(TransitionBlock * pTransitionBlock, int frameFlags) :
3413 m_gsCookie(GetProcessGSCookie()), m_frame(pTransitionBlock, frameFlags) { WRAPPER_NO_CONTRACT; }
3417 FrameWithCookie(Thread * pThread, OBJECTREF *pObjRefs, UINT numObjRefs, BOOL maybeInterior) :
3418 m_gsCookie(GetProcessGSCookie()), m_frame(pThread, pObjRefs, numObjRefs, maybeInterior) { WRAPPER_NO_CONTRACT; }
3420 FrameWithCookie(OBJECTREF *pObjRefs, UINT numObjRefs, BOOL maybeInterior) :
3421 m_gsCookie(GetProcessGSCookie()), m_frame(pObjRefs, numObjRefs, maybeInterior) { WRAPPER_NO_CONTRACT; }
3423 // GCSafeCollectionFrame
3424 FrameWithCookie(GCSafeCollection *gcSafeCollection) :
3425 m_gsCookie(GetProcessGSCookie()), m_frame(gcSafeCollection) { WRAPPER_NO_CONTRACT; }
3427 #ifdef FEATURE_INTERPRETER
3429 FrameWithCookie(Interpreter* interp) :
3430 m_gsCookie(GetProcessGSCookie()), m_frame(interp) { WRAPPER_NO_CONTRACT; }
3434 FrameWithCookie(LPVOID returnAddress, Thread *thread, HijackArgs *args) :
3435 m_gsCookie(GetProcessGSCookie()), m_frame(returnAddress, thread, args) { WRAPPER_NO_CONTRACT; }
3437 #ifdef DEBUGGING_SUPPORTED
3439 FrameWithCookie(DebuggerEval *pDebuggerEval, TADDR returnAddress, BOOL showFrame) :
3440 m_gsCookie(GetProcessGSCookie()), m_frame(pDebuggerEval, returnAddress, showFrame) { WRAPPER_NO_CONTRACT; }
3441 #endif // DEBUGGING_SUPPORTED
3444 FrameWithCookie(T_CONTEXT * pContext, Thread *thread) :
3445 m_gsCookie(GetProcessGSCookie()), m_frame(pContext, thread) { WRAPPER_NO_CONTRACT; }
3447 #ifndef DACCESS_COMPILE
3448 // GSCookie for HelperMethodFrames is initialized in a common HelperMethodFrame init method
3450 // HelperMethodFrame
3451 FORCEINLINE FrameWithCookie(void* fCallFtnEntry, unsigned attribs = 0) :
3452 m_frame(fCallFtnEntry, attribs) { WRAPPER_NO_CONTRACT; }
3454 // HelperMethodFrame_1OBJ
3455 FORCEINLINE FrameWithCookie(void* fCallFtnEntry, unsigned attribs, OBJECTREF * aGCPtr1) :
3456 m_frame(fCallFtnEntry, attribs, aGCPtr1) { WRAPPER_NO_CONTRACT; }
3458 // HelperMethodFrame_2OBJ
3459 FORCEINLINE FrameWithCookie(void* fCallFtnEntry, unsigned attribs, OBJECTREF * aGCPtr1, OBJECTREF * aGCPtr2) :
3460 m_frame(fCallFtnEntry, attribs, aGCPtr1, aGCPtr2) { WRAPPER_NO_CONTRACT; }
3462 // HelperMethodFrame_3OBJ
3463 FORCEINLINE FrameWithCookie(void* fCallFtnEntry, unsigned attribs, OBJECTREF * aGCPtr1, OBJECTREF * aGCPtr2, OBJECTREF * aGCPtr3) :
3464 m_frame(fCallFtnEntry, attribs, aGCPtr1, aGCPtr2, aGCPtr3) { WRAPPER_NO_CONTRACT; }
3466 // HelperMethodFrame_PROTECTOBJ
3467 FORCEINLINE FrameWithCookie(void* fCallFtnEntry, unsigned attribs, OBJECTREF* pObjRefs, int numObjRefs) :
3468 m_frame(fCallFtnEntry, attribs, pObjRefs, numObjRefs) { WRAPPER_NO_CONTRACT; }
3470 #endif // DACCESS_COMPILE
3472 // ProtectByRefsFrame
3473 FrameWithCookie(Thread * pThread, ByRefInfo * pByRefs) :
3474 m_gsCookie(GetProcessGSCookie()), m_frame(pThread, pByRefs) { WRAPPER_NO_CONTRACT; }
3476 // ProtectValueClassFrame
3477 FrameWithCookie(Thread * pThread, ValueClassInfo * pValueClasses) :
3478 m_gsCookie(GetProcessGSCookie()), m_frame(pThread, pValueClasses) { WRAPPER_NO_CONTRACT; }
3480 // ExceptionFilterFrame
3481 FrameWithCookie(size_t* pShadowSP) :
3482 m_gsCookie(GetProcessGSCookie()), m_frame(pShadowSP) { WRAPPER_NO_CONTRACT; }
3485 // AssumeByrefFromJITStack
3486 FrameWithCookie(OBJECTREF *pObjRef) :
3487 m_gsCookie(GetProcessGSCookie()), m_frame(pObjRef) { WRAPPER_NO_CONTRACT; }
3489 void SetAddrOfHaveCheckedRestoreState(BOOL* pDoneCheck)
3491 WRAPPER_NO_CONTRACT;
3492 m_frame.SetAddrOfHaveCheckedRestoreState(pDoneCheck);
3498 // Overload some common Frame methods for easy redirection
3501 void Push() { WRAPPER_NO_CONTRACT; m_frame.Push(); }
3502 void Pop() { WRAPPER_NO_CONTRACT; m_frame.Pop(); }
3503 void Push(Thread * pThread) { WRAPPER_NO_CONTRACT; m_frame.Push(pThread); }
3504 void Pop(Thread * pThread) { WRAPPER_NO_CONTRACT; m_frame.Pop(pThread); }
3505 PCODE GetReturnAddress() { WRAPPER_NO_CONTRACT; return m_frame.GetReturnAddress(); }
3506 T_CONTEXT * GetContext() { WRAPPER_NO_CONTRACT; return m_frame.GetContext(); }
3507 FrameType* operator&() { LIMITED_METHOD_CONTRACT; return &m_frame; }
3508 LazyMachState * MachineState() { WRAPPER_NO_CONTRACT; return m_frame.MachineState(); }
3509 Thread * GetThread() { WRAPPER_NO_CONTRACT; return m_frame.GetThread(); }
3510 BOOL InsureInit(bool initialInit, struct MachState* unwindState)
3511 { WRAPPER_NO_CONTRACT; return m_frame.InsureInit(initialInit, unwindState); }
3512 void Poll() { WRAPPER_NO_CONTRACT; m_frame.Poll(); }
3513 void SetStackPointerPtr(TADDR sp) { WRAPPER_NO_CONTRACT; m_frame.SetStackPointerPtr(sp); }
3514 void InitAndLink(T_CONTEXT *pContext) { WRAPPER_NO_CONTRACT; m_frame.InitAndLink(pContext); }
3515 void Init(Thread *pThread, OBJECTREF *pObjRefs, UINT numObjRefs, BOOL maybeInterior)
3516 { WRAPPER_NO_CONTRACT; m_frame.Init(pThread, pObjRefs, numObjRefs, maybeInterior); }
3517 ValueClassInfo ** GetValueClassInfoList() { WRAPPER_NO_CONTRACT; return m_frame.GetValueClassInfoList(); }
3521 // Access to the underlying Frame
3522 // You should only need to use this if none of the above overloads work for you
3523 // Consider adding the required overload to the list above
3526 FrameType& operator->() { LIMITED_METHOD_CONTRACT; return m_frame; }
3529 // Since the "&" operator is overloaded, use this function to get to the
3530 // address of FrameWithCookie, rather than that of FrameWithCookie::m_frame.
3531 GSCookie * GetGSCookiePtr() { LIMITED_METHOD_CONTRACT; return &m_gsCookie; }
3534 //------------------------------------------------------------------------
3535 // These macros GC-protect OBJECTREF pointers on the EE's behalf.
3536 // In between these macros, the GC can move but not discard the protected
3537 // objects. If the GC moves an object, it will update the guarded OBJECTREF's.
3540 // OBJECTREF or = <some valid objectref>;
3541 // GCPROTECT_BEGIN(or);
3543 // ...<do work that can trigger GC>...
3548 // These macros can also protect multiple OBJECTREF's if they're packaged
3549 // into a structure:
3556 // GCPROTECT_BEGIN(gc);
3563 // - GCPROTECT_BEGININTERIOR() can be used in place of GCPROTECT_BEGIN()
3564 // to handle the case where one or more of the OBJECTREFs is potentially
3565 // an interior pointer. This is a rare situation, because boxing would
3566 // normally prevent us from encountering it. Be aware that the OBJECTREFs
3567 // we protect are not validated in this situation.
3569 // - GCPROTECT_ARRAY_BEGIN() can be used when an array of object references
3570 // is allocated on the stack. The pointer to the first element is passed
3571 // along with the number of elements in the array.
3573 // - The argument to GCPROTECT_BEGIN should be an lvalue because it
3574 // uses "sizeof" to count the OBJECTREF's.
3576 // - GCPROTECT_BEGIN spiritually violates our normal convention of not passing
3577 // non-const refernce arguments. Unfortunately, this is necessary in
3578 // order for the sizeof thing to work.
3580 // - GCPROTECT_BEGIN does _not_ zero out the OBJECTREF's. You must have
3581 // valid OBJECTREF's when you invoke this macro.
3583 // - GCPROTECT_BEGIN begins a new C nesting block. Besides allowing
3584 // GCPROTECT_BEGIN's to nest, it also has the advantage of causing
3585 // a compiler error if you forget to code a maching GCPROTECT_END.
3587 // - If you are GCPROTECTing something, it means you are expecting a GC to occur.
3588 // So we assert that GC is not forbidden. If you hit this assert, you probably need
3589 // a HELPER_METHOD_FRAME to protect the region that can cause the GC.
3590 //------------------------------------------------------------------------
3592 #ifndef DACCESS_COMPILE
3595 // Suppress prefast warning #6384: Dividing sizeof a pointer by another value
3596 #pragma warning(disable:6384)
3597 #endif /*_PREFAST_ */
3599 #define GCPROTECT_BEGIN(ObjRefStruct) do { \
3600 FrameWithCookie<GCFrame> __gcframe( \
3601 (OBJECTREF*)&(ObjRefStruct), \
3602 sizeof(ObjRefStruct)/sizeof(OBJECTREF), \
3604 /* work around unreachable code warning */ \
3605 if (true) { DEBUG_ASSURE_NO_RETURN_BEGIN(GCPROTECT)
3607 #define GCPROTECT_BEGIN_THREAD(pThread, ObjRefStruct) do { \
3608 FrameWithCookie<GCFrame> __gcframe( \
3610 (OBJECTREF*)&(ObjRefStruct), \
3611 sizeof(ObjRefStruct)/sizeof(OBJECTREF), \
3613 /* work around unreachable code warning */ \
3614 if (true) { DEBUG_ASSURE_NO_RETURN_BEGIN(GCPROTECT)
3616 #define GCPROTECT_ARRAY_BEGIN(ObjRefArray,cnt) do { \
3617 FrameWithCookie<GCFrame> __gcframe( \
3618 (OBJECTREF*)&(ObjRefArray), \
3619 cnt * sizeof(ObjRefArray) / sizeof(OBJECTREF), \
3621 /* work around unreachable code warning */ \
3622 if (true) { DEBUG_ASSURE_NO_RETURN_BEGIN(GCPROTECT)
3624 #define GCPROTECT_BEGININTERIOR(ObjRefStruct) do { \
3625 /* work around Wsizeof-pointer-div warning as we */ \
3626 /* mean to capture pointer or object size */ \
3627 UINT subjectSize = sizeof(ObjRefStruct); \
3628 FrameWithCookie<GCFrame> __gcframe( \
3629 (OBJECTREF*)&(ObjRefStruct), \
3630 subjectSize/sizeof(OBJECTREF), \
3632 /* work around unreachable code warning */ \
3633 if (true) { DEBUG_ASSURE_NO_RETURN_BEGIN(GCPROTECT)
3635 #define GCPROTECT_BEGININTERIOR_ARRAY(ObjRefArray,cnt) do { \
3636 FrameWithCookie<GCFrame> __gcframe( \
3637 (OBJECTREF*)&(ObjRefArray), \
3640 /* work around unreachable code warning */ \
3641 if (true) { DEBUG_ASSURE_NO_RETURN_BEGIN(GCPROTECT)
3644 #define GCPROTECT_END() \
3645 DEBUG_ASSURE_NO_RETURN_END(GCPROTECT) } \
3646 __gcframe.Pop(); } while(0)
3649 #else // #ifndef DACCESS_COMPILE
3651 #define GCPROTECT_BEGIN(ObjRefStruct)
3652 #define GCPROTECT_ARRAY_BEGIN(ObjRefArray,cnt)
3653 #define GCPROTECT_BEGININTERIOR(ObjRefStruct)
3654 #define GCPROTECT_END()
3656 #endif // #ifndef DACCESS_COMPILE
3659 #define ASSERT_ADDRESS_IN_STACK(address) _ASSERTE (Thread::IsAddressInCurrentStack (address));
3661 #if defined (_DEBUG) && !defined (DACCESS_COMPILE)
3662 #define ASSUME_BYREF_FROM_JIT_STACK_BEGIN(__objRef) \
3663 /* make sure we are only called inside an FCall */ \
3664 if (__me == 0) {}; \
3665 /* make sure the address is in stack. If the address is an interior */ \
3666 /*pointer points to GC heap, the FCall still needs to protect it explicitly */ \
3667 ASSERT_ADDRESS_IN_STACK (__objRef); \
3669 FrameWithCookie<AssumeByrefFromJITStack> __dummyAssumeByrefFromJITStack ((__objRef)); \
3670 __dummyAssumeByrefFromJITStack.Push (); \
3671 /* work around unreachable code warning */ \
3672 if (true) { DEBUG_ASSURE_NO_RETURN_BEGIN(GC_PROTECT)
3674 #define ASSUME_BYREF_FROM_JIT_STACK_END() \
3675 DEBUG_ASSURE_NO_RETURN_END(GC_PROTECT) } \
3676 __dummyAssumeByrefFromJITStack.Pop(); } while(0)
3677 #else //defined (_DEBUG) && !defined (DACCESS_COMPILE)
3678 #define ASSUME_BYREF_FROM_JIT_STACK_BEGIN(__objRef)
3679 #define ASSUME_BYREF_FROM_JIT_STACK_END()
3680 #endif //defined (_DEBUG) && !defined (DACCESS_COMPILE)
3682 //------------------------------------------------------------------------
3684 #if defined(FRAMES_TURNED_FPO_ON)
3685 #pragma optimize("", on) // Go back to command line default optimizations
3686 #undef FRAMES_TURNED_FPO_ON
3690 #include "crossloaderallocatorhash.inl"
3692 #endif //__frames_h__