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"
286 #include "method.hpp"
287 #include "stackwalk.h"
291 #include "callingconvention.h"
293 // Forward references
295 class FieldMarshaler;
296 class FramedMethodFrame;
297 typedef VPTR(class FramedMethodFrame) PTR_FramedMethodFrame;
300 class UMThunkMarshInfo;
302 struct ResolveCacheElem;
303 #if defined(DACCESS_COMPILE)
304 class DacDbiInterfaceImpl;
305 #endif // DACCESS_COMPILE
306 #ifdef FEATURE_COMINTEROP
307 class ComMethodFrame;
308 class ComCallMethodDesc;
309 #endif // FEATURE_COMINTEROP
311 // Note: the value (-1) is used to generate the largest possible pointer value: this keeps frame addresses
312 // increasing upward. Because we want to ensure that we don't accidentally change this, we have a C_ASSERT
313 // in stackwalk.cpp. Since it requires constant values as args, we need to define FRAME_TOP in two steps.
314 // First we define FRAME_TOP_VALUE which we'll use when we do the compile-time check, then we'll define
315 // FRAME_TOP in terms of FRAME_TOP_VALUE. Defining FRAME_TOP as a PTR_Frame means we don't have to type cast
316 // whenever we compare it to a PTR_Frame value (the usual use of the value).
317 #define FRAME_TOP_VALUE ~0 // we want to say -1 here, but gcc has trouble with the signed value
318 #define FRAME_TOP (PTR_Frame(FRAME_TOP_VALUE))
320 #ifndef DACCESS_COMPILE
322 #if defined(FEATURE_PAL) && !defined(CROSSGEN_COMPILE)
324 #define DEFINE_DTOR(klass) \
326 virtual ~klass() { PopIfChained(); }
330 #define DEFINE_DTOR(klass)
332 #endif // FEATURE_PAL && !CROSSGEN_COMPILE
334 #define DEFINE_VTABLE_GETTER(klass) \
336 static TADDR GetMethodFrameVPtr() { \
337 LIMITED_METHOD_CONTRACT; \
338 klass boilerplate(false); \
339 return *((TADDR*)&boilerplate); \
341 klass(bool dummy) { LIMITED_METHOD_CONTRACT; }
343 #define DEFINE_VTABLE_GETTER_AND_DTOR(klass) \
344 DEFINE_VTABLE_GETTER(klass) \
347 #define DEFINE_VTABLE_GETTER_AND_CTOR(klass) \
348 DEFINE_VTABLE_GETTER(klass) \
350 klass() { LIMITED_METHOD_CONTRACT; }
352 #define DEFINE_VTABLE_GETTER_AND_CTOR_AND_DTOR(klass) \
353 DEFINE_VTABLE_GETTER_AND_DTOR(klass) \
355 klass() { LIMITED_METHOD_CONTRACT; }
359 #define DEFINE_VTABLE_GETTER(klass) \
361 static TADDR GetMethodFrameVPtr() { \
362 LIMITED_METHOD_CONTRACT; \
363 return klass::VPtrTargetVTable(); \
366 #define DEFINE_VTABLE_GETTER_AND_DTOR(klass) \
367 DEFINE_VTABLE_GETTER(klass) \
369 #define DEFINE_VTABLE_GETTER_AND_CTOR(klass) \
370 DEFINE_VTABLE_GETTER(klass) \
372 #define DEFINE_VTABLE_GETTER_AND_CTOR_AND_DTOR(klass) \
373 DEFINE_VTABLE_GETTER_AND_CTOR(klass) \
375 #endif // #ifndef DACCESS_COMPILE
377 //-----------------------------------------------------------------------------
378 // For reporting on types of frames at runtime.
385 typedef DPTR(FrameTypeName) PTR_FrameTypeName;
387 //-----------------------------------------------------------------------------
388 // Frame depends on the location of its vtable within the object. This
389 // superclass ensures that the vtable for Frame objects is in the same
390 // location under both MSVC and GCC.
391 //-----------------------------------------------------------------------------
395 VPTR_BASE_VTABLE_CLASS(FrameBase)
398 FrameBase() {LIMITED_METHOD_CONTRACT; }
400 virtual void GcScanRoots(promote_func *fn, ScanContext* sc) {
401 LIMITED_METHOD_CONTRACT;
402 // Nothing to protect
405 #ifdef DACCESS_COMPILE
406 virtual void EnumMemoryRegions(CLRDataEnumMemoryFlags flags) = 0;
410 //------------------------------------------------------------------------
411 // Frame defines methods common to all frame types. There are no actual
412 // instances of root frames.
413 //------------------------------------------------------------------------
415 class Frame : public FrameBase
417 friend class CheckAsmOffsets;
418 #ifdef DACCESS_COMPILE
419 friend void Thread::EnumMemoryRegions(CLRDataEnumMemoryFlags flags);
422 VPTR_ABSTRACT_VTABLE_CLASS(Frame, FrameBase)
426 //------------------------------------------------------------------------
427 // Special characteristics of a frame
428 //------------------------------------------------------------------------
431 FRAME_ATTR_EXCEPTION = 1, // This frame caused an exception
432 FRAME_ATTR_OUT_OF_LINE = 2, // The exception out of line (IP of the frame is not correct)
433 FRAME_ATTR_FAULTED = 4, // Exception caused by Win32 fault
434 FRAME_ATTR_RESUMABLE = 8, // We may resume from this frame
435 FRAME_ATTR_CAPTURE_DEPTH_2 = 0x10, // This is a helperMethodFrame and the capture occurred at depth 2
436 FRAME_ATTR_EXACT_DEPTH = 0x20, // This is a helperMethodFrame and a jit helper, but only crawl to the given depth
437 FRAME_ATTR_NO_THREAD_ABORT = 0x40, // This is a helperMethodFrame that should not trigger thread aborts on entry
439 virtual unsigned GetFrameAttribs()
441 LIMITED_METHOD_DAC_CONTRACT;
442 return FRAME_ATTR_NONE;
445 //------------------------------------------------------------------------
446 // Performs cleanup on an exception unwind
447 //------------------------------------------------------------------------
448 #ifndef DACCESS_COMPILE
449 virtual void ExceptionUnwind()
451 // Nothing to do here.
452 LIMITED_METHOD_CONTRACT;
456 // Should be overridden to return TRUE if the frame contains register
457 // state of the caller.
458 virtual BOOL NeedsUpdateRegDisplay()
463 //------------------------------------------------------------------------
464 // Is this a frame used on transition to native code from jitted code?
465 //------------------------------------------------------------------------
466 virtual BOOL IsTransitionToNativeFrame()
468 LIMITED_METHOD_CONTRACT;
472 virtual MethodDesc *GetFunction()
474 LIMITED_METHOD_DAC_CONTRACT;
478 virtual Assembly *GetAssembly()
481 MethodDesc *pMethod = GetFunction();
483 return pMethod->GetModule()->GetAssembly();
488 // indicate the current X86 IP address within the current method
489 // return 0 if the information is not available
490 virtual PTR_BYTE GetIP()
492 LIMITED_METHOD_CONTRACT;
496 // DACCESS: GetReturnAddressPtr should return the
497 // target address of the return address in the frame.
498 virtual TADDR GetReturnAddressPtr()
500 LIMITED_METHOD_DAC_CONTRACT;
504 virtual PCODE GetReturnAddress()
507 TADDR ptr = GetReturnAddressPtr();
508 return (ptr != NULL) ? *PTR_PCODE(ptr) : NULL;
511 virtual PTR_Context* GetReturnContextAddr()
513 LIMITED_METHOD_DAC_CONTRACT;
517 Context *GetReturnContext()
521 PTR_Context* ppReturnContext = GetReturnContextAddr();
522 if (! ppReturnContext)
524 return *ppReturnContext;
527 AppDomain *GetReturnDomain()
532 if (! GetReturnContext())
534 return GetReturnContext()->GetDomain();
537 #ifndef DACCESS_COMPILE
538 virtual Object **GetReturnExecutionContextAddr()
540 LIMITED_METHOD_CONTRACT;
544 void SetReturnAddress(TADDR val)
547 TADDR ptr = GetReturnAddressPtr();
548 _ASSERTE(ptr != NULL);
552 #ifndef DACCESS_COMPILE
553 void SetReturnContext(Context *pReturnContext)
556 PTR_Context* ppReturnContext = GetReturnContextAddr();
557 _ASSERTE(ppReturnContext);
558 *ppReturnContext = pReturnContext;
562 void SetReturnExecutionContext(OBJECTREF ref)
565 Object **pRef = GetReturnExecutionContextAddr();
567 *pRef = OBJECTREFToObject(ref);
570 OBJECTREF GetReturnExecutionContext()
573 Object **pRef = GetReturnExecutionContextAddr();
577 return ObjectToOBJECTREF(*pRef);
579 #endif // #ifndef DACCESS_COMPILE
581 PTR_GSCookie GetGSCookiePtr()
584 return dac_cast<PTR_GSCookie>(dac_cast<TADDR>(this) + GetOffsetOfGSCookie());
587 static int GetOffsetOfGSCookie()
589 LIMITED_METHOD_DAC_CONTRACT;
590 return -(int)sizeof(GSCookie);
593 static bool HasValidVTablePtr(Frame * pFrame);
594 static PTR_GSCookie SafeGetGSCookiePtr(Frame * pFrame);
598 // Callers, note that the REGDISPLAY parameter is actually in/out. While
599 // UpdateRegDisplay is generally used to fill out the REGDISPLAY parameter, some
600 // overrides (e.g., code:ResumableFrame::UpdateRegDisplay) will actually READ what
601 // you pass in. So be sure to pass in a valid or zeroed out REGDISPLAY.
602 virtual void UpdateRegDisplay(const PREGDISPLAY)
604 LIMITED_METHOD_DAC_CONTRACT;
608 //------------------------------------------------------------------------
610 //------------------------------------------------------------------------
617 TT_M2U, // we can safely cast to a FramedMethodFrame
618 TT_U2M, // we can safely cast to a UnmanagedToManagedFrame
619 TT_AppDomain, // transitioniting between AppDomains.
620 TT_InternalCall, // calling into the CLR (ecall/fcall).
623 // Get the type of transition.
625 virtual ETransitionType GetTransitionType()
627 LIMITED_METHOD_DAC_CONTRACT;
643 // HMFs and derived classes should use this so the profiling API knows it needs
644 // to ensure HMF-specific lazy initialization gets done w/out re-entering to the host.
645 TYPE_HELPER_METHOD_FRAME,
650 virtual int GetFrameType()
652 LIMITED_METHOD_DAC_CONTRACT;
653 return TYPE_INTERNAL;
656 // When stepping into a method, various other methods may be called.
657 // These are refererred to as interceptors. They are all invoked
658 // with frames of various types. GetInterception() indicates whether
659 // the frame was set up for execution of such interceptors
664 INTERCEPTION_CLASS_INIT,
665 INTERCEPTION_EXCEPTION,
666 INTERCEPTION_CONTEXT,
667 INTERCEPTION_SECURITY,
668 INTERCEPTION_PRESTUB,
674 virtual Interception GetInterception()
676 LIMITED_METHOD_DAC_CONTRACT;
677 return INTERCEPTION_NONE;
680 // Return information about an unmanaged call the frame
682 // ip - the unmanaged routine which will be called
683 // returnIP - the address in the stub which the unmanaged routine
685 // returnSP - the location returnIP is pushed onto the stack
688 virtual void GetUnmanagedCallSite(TADDR* ip,
692 LIMITED_METHOD_CONTRACT;
703 // Return where the frame will execute next - the result is filled
704 // into the given "trace" structure. The frame is responsible for
705 // detecting where it is in its execution lifetime.
706 virtual BOOL TraceFrame(Thread *thread, BOOL fromPatch,
707 TraceDestination *trace, REGDISPLAY *regs)
709 LIMITED_METHOD_CONTRACT;
710 LOG((LF_CORDB, LL_INFO10000,
711 "Default TraceFrame always returns false.\n"));
715 #ifdef DACCESS_COMPILE
716 virtual void EnumMemoryRegions(CLRDataEnumMemoryFlags flags)
721 // Many frames store a MethodDesc pointer in m_Datum
722 // so pick that up automatically.
723 MethodDesc* func = GetFunction();
726 func->EnumMemoryRegions(flags);
729 // Include the NegSpace
730 GSCookie * pGSCookie = GetGSCookiePtr();
731 _ASSERTE(FitsIn<ULONG32>(PBYTE(pGSCookie) - PBYTE(this)));
732 ULONG32 negSpaceSize = static_cast<ULONG32>(PBYTE(pGSCookie) - PBYTE(this));
733 DacEnumMemoryRegion(dac_cast<TADDR>(this) - negSpaceSize, negSpaceSize);
737 //---------------------------------------------------------------
738 // Expose key offsets and values for stub generation.
739 //---------------------------------------------------------------
740 static BYTE GetOffsetOfNextLink()
743 size_t ofs = offsetof(class Frame, m_Next);
744 _ASSERTE(FitsInI1(ofs));
748 // get your VTablePointer (can be used to check what type the frame is)
751 LIMITED_METHOD_DAC_CONTRACT;
752 return VPTR_HOST_VTABLE_TO_TADDR(*(LPVOID*)this);
755 #if defined(_DEBUG) && !defined(DACCESS_COMPILE)
756 virtual BOOL Protects(OBJECTREF *ppObjectRef)
758 LIMITED_METHOD_CONTRACT;
763 #ifndef DACCESS_COMPILE
764 // Link and Unlink this frame
767 VOID Push(Thread *pThread);
768 VOID Pop(Thread *pThread);
769 #endif // DACCESS_COMPILE
773 static BOOL ShouldLogTransitions() { WRAPPER_NO_CONTRACT; return LoggingOn(LF_STUBS, LL_INFO1000000); }
774 static void __stdcall LogTransition(Frame* frame);
775 void LogFrame(int LF, int LL); // General purpose logging.
776 void LogFrameChain(int LF, int LL); // Log the whole chain.
777 virtual const char* GetFrameTypeName() {return NULL;}
778 static PTR_CSTR GetFrameTypeName(TADDR vtbl);
781 //------------------------------------------------------------------------
782 // Returns the address of a security object or
783 // null if there is no space for an object on this frame.
784 //------------------------------------------------------------------------
785 virtual OBJECTREF *GetAddrOfSecurityDesc()
787 LIMITED_METHOD_CONTRACT;
792 // Pointer to the next frame up the stack.
795 PTR_Frame m_Next; // offset +4
798 PTR_Frame PtrNextFrame() { return m_Next; }
801 // Because JIT-method activations cannot be expressed as Frames,
802 // everyone must use the StackCrawler to walk the frame chain
803 // reliably. We'll expose the Next method only to the StackCrawler
804 // to prevent mistakes.
805 /*<TODO>@NICE: Restrict "friendship" again to the StackWalker method;
806 not done because of circular dependency with threads.h</TODO>
808 // friend Frame* Thread::StackWalkFrames(PSTACKWALKFRAMESCALLBACK pCallback, VOID *pData);
810 friend void CrawlFrame::GotoNextFrame();
811 friend class StackFrameIterator;
812 friend class TailCallFrame;
813 friend class AppDomain;
814 friend VOID RealCOMPlusThrow(OBJECTREF
815 #ifdef FEATURE_CORRUPTING_EXCEPTIONS
816 , CorruptionSeverity severity
817 #endif // FEATURE_CORRUPTING_EXCEPTIONS
819 friend FCDECL0(VOID, JIT_StressGC);
821 friend LONG WINAPI CLRVectoredExceptionHandlerShim(PEXCEPTION_POINTERS pExceptionInfo);
824 friend Thread * __stdcall JIT_InitPInvokeFrame(InlinedCallFrame *pFrame, PTR_VOID StubSecretArg);
826 #ifdef WIN64EXCEPTIONS
827 friend class ExceptionTracker;
829 #if defined(DACCESS_COMPILE)
830 friend class DacDbiInterfaceImpl;
831 #endif // DACCESS_COMPILE
832 #ifdef FEATURE_COMINTEROP
833 friend void COMToCLRWorkerBodyWithADTransition(Thread *pThread, ComMethodFrame *pFrame, ComCallWrapper *pWrap, UINT64 *pRetValOut);
834 #endif // FEATURE_COMINTEROP
838 LIMITED_METHOD_DAC_CONTRACT;
843 // Frame is considered an abstract class: this protected constructor
844 // causes any attempt to instantiate one to fail at compile-time.
846 : m_Next(dac_cast<PTR_Frame>(nullptr))
848 LIMITED_METHOD_CONTRACT;
851 #if defined(FEATURE_PAL) && !defined(DACCESS_COMPILE) && !defined(CROSSGEN_COMPILE)
852 virtual ~Frame() { LIMITED_METHOD_CONTRACT; }
855 #endif // FEATURE_PAL && !DACCESS_COMPILE && !CROSSGEN_COMPILE
859 //-----------------------------------------------------------------------------
860 // This frame provides context for a frame that
861 // took an exception that is going to be resumed.
863 // It is necessary to create this frame if garbage
864 // collection may happen during handling of the
865 // exception. The FRAME_ATTR_RESUMABLE flag tells
866 // the GC that the preceding frame needs to be treated
867 // like the top of stack (with the important implication that
868 // caller-save-regsiters will be potential roots).
869 //-----------------------------------------------------------------------------
870 #ifdef FEATURE_HIJACK
871 //-----------------------------------------------------------------------------
873 class ResumableFrame : public Frame
875 VPTR_VTABLE_CLASS(ResumableFrame, Frame)
878 #ifndef DACCESS_COMPILE
879 ResumableFrame(T_CONTEXT* regs) {
880 LIMITED_METHOD_CONTRACT;
885 virtual TADDR GetReturnAddressPtr();
887 virtual BOOL NeedsUpdateRegDisplay()
892 virtual void UpdateRegDisplay(const PREGDISPLAY pRD);
894 virtual unsigned GetFrameAttribs() {
895 LIMITED_METHOD_DAC_CONTRACT;
896 return FRAME_ATTR_RESUMABLE; // Treat the next frame as the top frame.
899 T_CONTEXT *GetContext() {
900 LIMITED_METHOD_DAC_CONTRACT;
904 #ifdef DACCESS_COMPILE
905 virtual void EnumMemoryRegions(CLRDataEnumMemoryFlags flags)
908 Frame::EnumMemoryRegions(flags);
916 // Keep as last entry in class
917 DEFINE_VTABLE_GETTER_AND_CTOR_AND_DTOR(ResumableFrame)
921 //-----------------------------------------------------------------------------
922 // RedirectedThreadFrame
923 //-----------------------------------------------------------------------------
925 class RedirectedThreadFrame : public ResumableFrame
927 VPTR_VTABLE_CLASS(RedirectedThreadFrame, ResumableFrame)
928 VPTR_UNIQUE(VPTR_UNIQUE_RedirectedThreadFrame)
931 #ifndef DACCESS_COMPILE
932 RedirectedThreadFrame(T_CONTEXT *regs) : ResumableFrame(regs) {
933 LIMITED_METHOD_CONTRACT;
936 virtual void ExceptionUnwind();
939 // Keep as last entry in class
940 DEFINE_VTABLE_GETTER_AND_CTOR_AND_DTOR(RedirectedThreadFrame)
943 typedef DPTR(RedirectedThreadFrame) PTR_RedirectedThreadFrame;
945 inline BOOL ISREDIRECTEDTHREAD(Thread * thread)
948 return (thread->GetFrame() != FRAME_TOP &&
949 thread->GetFrame()->GetVTablePtr() ==
950 RedirectedThreadFrame::GetMethodFrameVPtr());
953 inline T_CONTEXT * GETREDIRECTEDCONTEXT(Thread * thread)
956 _ASSERTE(ISREDIRECTEDTHREAD(thread));
957 return dac_cast<PTR_RedirectedThreadFrame>(thread->GetFrame())->GetContext();
960 //------------------------------------------------------------------------
961 #else // FEATURE_HIJACK
962 //------------------------------------------------------------------------
964 inline BOOL ISREDIRECTEDTHREAD(Thread * thread) { LIMITED_METHOD_CONTRACT; return FALSE; }
965 inline CONTEXT * GETREDIRECTEDCONTEXT(Thread * thread) { LIMITED_METHOD_CONTRACT; return (CONTEXT*) NULL; }
967 //------------------------------------------------------------------------
968 #endif // FEATURE_HIJACK
969 //------------------------------------------------------------------------
970 // This frame represents a transition from one or more nested frameless
971 // method calls to either a EE runtime helper function or a framed method.
972 // Because most stackwalks from the EE start with a full-fledged frame,
973 // anything but the most trivial call into the EE has to push this
974 // frame in order to prevent the frameless methods inbetween from
976 //------------------------------------------------------------------------
978 class TransitionFrame : public Frame
980 VPTR_ABSTRACT_VTABLE_CLASS(TransitionFrame, Frame)
983 virtual TADDR GetTransitionBlock() = 0;
985 // DACCESS: GetReturnAddressPtr should return the
986 // target address of the return address in the frame.
987 virtual TADDR GetReturnAddressPtr()
989 LIMITED_METHOD_DAC_CONTRACT;
990 return GetTransitionBlock() + TransitionBlock::GetOffsetOfReturnAddress();
993 //---------------------------------------------------------------
994 // Get the "this" object.
995 //---------------------------------------------------------------
999 Object* obj = PTR_Object(*PTR_TADDR(GetAddrOfThis()));
1000 return ObjectToOBJECTREF(obj);
1003 PTR_OBJECTREF GetThisPtr()
1005 WRAPPER_NO_CONTRACT;
1006 return PTR_OBJECTREF(GetAddrOfThis());
1009 //---------------------------------------------------------------
1010 // Get the extra info for shared generic code.
1011 //---------------------------------------------------------------
1012 PTR_VOID GetParamTypeArg();
1014 protected: // we don't want people using this directly
1015 //---------------------------------------------------------------
1016 // Get the address of the "this" object. WARNING!!! Whether or not "this"
1017 // is gc-protected is depends on the frame type!!!
1018 //---------------------------------------------------------------
1019 TADDR GetAddrOfThis();
1022 //---------------------------------------------------------------
1023 // For vararg calls, return cookie.
1024 //---------------------------------------------------------------
1025 VASigCookie *GetVASigCookie();
1027 CalleeSavedRegisters *GetCalleeSavedRegisters()
1029 LIMITED_METHOD_DAC_CONTRACT;
1030 return dac_cast<PTR_CalleeSavedRegisters>(
1031 GetTransitionBlock() + TransitionBlock::GetOffsetOfCalleeSavedRegisters());
1034 ArgumentRegisters *GetArgumentRegisters()
1036 LIMITED_METHOD_DAC_CONTRACT;
1037 return dac_cast<PTR_ArgumentRegisters>(
1038 GetTransitionBlock() + TransitionBlock::GetOffsetOfArgumentRegisters());
1043 LIMITED_METHOD_DAC_CONTRACT;
1044 return GetTransitionBlock() + sizeof(TransitionBlock);
1047 virtual BOOL NeedsUpdateRegDisplay()
1052 virtual void UpdateRegDisplay(const PREGDISPLAY);
1054 void UpdateRegDisplayHelper(const PREGDISPLAY, UINT cbStackPop);
1057 #if defined (_DEBUG) && !defined (DACCESS_COMPILE)
1058 virtual BOOL Protects(OBJECTREF *ppORef);
1059 #endif //defined (_DEBUG) && defined (DACCESS_COMPILE)
1061 // For use by classes deriving from FramedMethodFrame.
1062 void PromoteCallerStack(promote_func* fn, ScanContext* sc);
1064 void PromoteCallerStackHelper(promote_func* fn, ScanContext* sc,
1065 MethodDesc * pMD, MetaSig *pmsig);
1067 void PromoteCallerStackUsingGCRefMap(promote_func* fn, ScanContext* sc, PTR_BYTE pGCRefMap);
1070 UINT CbStackPopUsingGCRefMap(PTR_BYTE pGCRefMap);
1076 LIMITED_METHOD_CONTRACT;
1080 //-----------------------------------------------------------------------
1081 // TransitionFrames for exceptions
1082 //-----------------------------------------------------------------------
1084 // The define USE_FEF controls how this class is used. Look for occurances
1087 class FaultingExceptionFrame : public Frame
1089 friend class CheckAsmOffsets;
1091 #ifndef WIN64EXCEPTIONS
1094 CalleeSavedRegisters m_regs;
1095 TADDR m_ReturnAddress;
1096 #else // _TARGET_X86_
1097 #error "Unsupported architecture"
1098 #endif // _TARGET_X86_
1099 #else // WIN64EXCEPTIONS
1100 BOOL m_fFilterExecuted; // Flag for FirstCallToHandler
1101 TADDR m_ReturnAddress;
1103 #endif // !WIN64EXCEPTIONS
1105 VPTR_VTABLE_CLASS(FaultingExceptionFrame, Frame)
1108 #ifndef DACCESS_COMPILE
1109 FaultingExceptionFrame() {
1110 LIMITED_METHOD_CONTRACT;
1114 virtual TADDR GetReturnAddressPtr()
1116 LIMITED_METHOD_DAC_CONTRACT;
1117 return PTR_HOST_MEMBER_TADDR(FaultingExceptionFrame, this, m_ReturnAddress);
1120 void Init(T_CONTEXT *pContext);
1121 void InitAndLink(T_CONTEXT *pContext);
1123 Interception GetInterception()
1125 LIMITED_METHOD_DAC_CONTRACT;
1126 return INTERCEPTION_EXCEPTION;
1129 unsigned GetFrameAttribs()
1131 LIMITED_METHOD_DAC_CONTRACT;
1132 return FRAME_ATTR_EXCEPTION | FRAME_ATTR_FAULTED;
1135 #ifndef WIN64EXCEPTIONS
1136 CalleeSavedRegisters *GetCalleeSavedRegisters()
1139 LIMITED_METHOD_DAC_CONTRACT;
1142 PORTABILITY_ASSERT("GetCalleeSavedRegisters");
1143 #endif // _TARGET_X86_
1145 #endif // WIN64EXCEPTIONS
1147 #ifdef WIN64EXCEPTIONS
1148 T_CONTEXT *GetExceptionContext ()
1150 LIMITED_METHOD_CONTRACT;
1154 BOOL * GetFilterExecutedFlag()
1156 LIMITED_METHOD_CONTRACT;
1157 return &m_fFilterExecuted;
1159 #endif // WIN64EXCEPTIONS
1161 virtual BOOL NeedsUpdateRegDisplay()
1166 virtual void UpdateRegDisplay(const PREGDISPLAY);
1168 // Keep as last entry in class
1169 DEFINE_VTABLE_GETTER_AND_DTOR(FaultingExceptionFrame)
1172 //-----------------------------------------------------------------------
1173 // Frame for debugger function evaluation
1175 // This frame holds a ptr to a DebuggerEval object which contains a copy
1176 // of the thread's context at the time it was hijacked for the func
1179 // UpdateRegDisplay updates all registers inthe REGDISPLAY, not just
1180 // the callee saved registers, because we can hijack for a func eval
1181 // at any point in a thread's execution.
1183 //-----------------------------------------------------------------------
1185 #ifdef DEBUGGING_SUPPORTED
1187 typedef DPTR(class DebuggerEval) PTR_DebuggerEval;
1189 class FuncEvalFrame : public Frame
1191 VPTR_VTABLE_CLASS(FuncEvalFrame, Frame)
1193 TADDR m_ReturnAddress;
1194 PTR_DebuggerEval m_pDebuggerEval;
1199 #ifndef DACCESS_COMPILE
1200 FuncEvalFrame(DebuggerEval *pDebuggerEval, TADDR returnAddress, BOOL showFrame)
1202 LIMITED_METHOD_CONTRACT;
1203 m_pDebuggerEval = pDebuggerEval;
1204 m_ReturnAddress = returnAddress;
1205 m_showFrame = showFrame;
1209 virtual BOOL IsTransitionToNativeFrame()
1211 LIMITED_METHOD_CONTRACT;
1215 virtual int GetFrameType()
1217 LIMITED_METHOD_DAC_CONTRACT;
1218 return TYPE_FUNC_EVAL;
1221 virtual unsigned GetFrameAttribs();
1223 virtual BOOL NeedsUpdateRegDisplay()
1228 virtual void UpdateRegDisplay(const PREGDISPLAY);
1230 virtual DebuggerEval * GetDebuggerEval();
1232 virtual TADDR GetReturnAddressPtr();
1237 * Returns if this frame should be returned as part of a stack trace to a debugger or not.
1242 LIMITED_METHOD_CONTRACT;
1247 // Keep as last entry in class
1248 DEFINE_VTABLE_GETTER_AND_CTOR_AND_DTOR(FuncEvalFrame)
1251 typedef VPTR(FuncEvalFrame) PTR_FuncEvalFrame;
1252 #endif // DEBUGGING_SUPPORTED
1254 //----------------------------------------------------------------------------------------------
1255 // A HelperMethodFrame is created by jit helper (Modified slightly it could be used
1256 // for native routines). This frame just does the callee saved register fixup.
1257 // It does NOT protect arguments; you must use GCPROTECT or one of the HelperMethodFrame
1258 // subclases. (see JitInterface for sample use, YOU CAN'T RETURN WHILE IN THE PROTECTED STATE!)
1259 //----------------------------------------------------------------------------------------------
1261 class HelperMethodFrame : public Frame
1263 VPTR_VTABLE_CLASS(HelperMethodFrame, Frame);
1266 #ifndef DACCESS_COMPILE
1267 // Lazy initialization of HelperMethodFrame. Need to
1268 // call InsureInit to complete initialization
1269 // If this is an FCall, the first param is the entry point for the FCALL.
1270 // The MethodDesc will be looked up form this (lazily), and this method
1271 // will be used in stack reporting, if this is not an FCall pass a 0
1272 FORCEINLINE HelperMethodFrame(void* fCallFtnEntry, unsigned attribs = 0)
1274 WRAPPER_NO_CONTRACT;
1275 // Most of the initialization is actually done in HelperMethodFrame::Push()
1276 INDEBUG(memset(&m_Attribs, 0xCC, sizeof(HelperMethodFrame) - offsetof(HelperMethodFrame, m_Attribs));)
1277 m_Attribs = attribs;
1278 m_FCallEntry = (TADDR)fCallFtnEntry;
1280 #endif // DACCESS_COMPILE
1282 virtual int GetFrameType()
1284 LIMITED_METHOD_DAC_CONTRACT;
1285 return TYPE_HELPER_METHOD_FRAME;
1288 virtual PCODE GetReturnAddress()
1290 LIMITED_METHOD_DAC_CONTRACT;
1292 if (!m_MachState.isValid())
1294 #if defined(DACCESS_COMPILE)
1295 MachState unwoundState;
1296 InsureInit(false, &unwoundState);
1297 return unwoundState.GetRetAddr();
1298 #else // !DACCESS_COMPILE
1299 _ASSERTE(!"HMF's should always be initialized in the non-DAC world.");
1302 #endif // !DACCESS_COMPILE
1305 return m_MachState.GetRetAddr();
1308 virtual MethodDesc* GetFunction();
1310 virtual BOOL NeedsUpdateRegDisplay()
1315 virtual void UpdateRegDisplay(const PREGDISPLAY);
1317 virtual Interception GetInterception()
1319 WRAPPER_NO_CONTRACT;
1320 LIMITED_METHOD_DAC_CONTRACT;
1321 if (GetFrameAttribs() & FRAME_ATTR_EXCEPTION)
1322 return(INTERCEPTION_EXCEPTION);
1323 return(INTERCEPTION_NONE);
1326 virtual ETransitionType GetTransitionType()
1328 LIMITED_METHOD_DAC_CONTRACT;
1329 return TT_InternalCall;
1333 void SetAddrOfHaveCheckedRestoreState(BOOL* pDoneCheck)
1335 m_pDoneCheck = pDoneCheck;
1338 BOOL HaveDoneConfirmStateCheck()
1340 LIMITED_METHOD_CONTRACT;
1341 _ASSERTE(m_pDoneCheck != NULL);
1342 return *m_pDoneCheck;
1345 void SetHaveDoneConfirmStateCheck()
1347 LIMITED_METHOD_CONTRACT;
1348 _ASSERTE(m_pDoneCheck != NULL);
1349 *m_pDoneCheck = TRUE;
1353 virtual unsigned GetFrameAttribs()
1355 LIMITED_METHOD_DAC_CONTRACT;
1359 #ifdef DACCESS_COMPILE
1360 virtual void EnumMemoryRegions(CLRDataEnumMemoryFlags flags)
1362 WRAPPER_NO_CONTRACT;
1363 Frame::EnumMemoryRegions(flags);
1367 #ifndef DACCESS_COMPILE
1371 FORCEINLINE void Poll()
1373 WRAPPER_NO_CONTRACT;
1374 if (m_pThread->CatchAtSafePointOpportunistic())
1377 #endif // DACCESS_COMPILE
1379 BOOL InsureInit(bool initialInit, struct MachState* unwindState, HostCallPreference hostCallPreference = AllowHostCalls);
1381 LazyMachState * MachineState() {
1382 LIMITED_METHOD_CONTRACT;
1383 return &m_MachState;
1386 Thread * GetThread() {
1387 LIMITED_METHOD_CONTRACT;
1392 // Slow paths of Push/Pop are factored into a separate functions for better perf.
1393 NOINLINE void PushSlowHelper();
1394 NOINLINE void PopSlowHelper();
1397 PTR_MethodDesc m_pMD;
1399 INDEBUG(BOOL* m_pDoneCheck;)
1400 PTR_Thread m_pThread;
1401 TADDR m_FCallEntry; // used to determine our identity for stack traces
1403 LazyMachState m_MachState; // pRetAddr points to the return address and the stack arguments
1405 // Keep as last entry in class
1406 DEFINE_VTABLE_GETTER_AND_CTOR_AND_DTOR(HelperMethodFrame)
1409 // Restores registers saved in m_MachState
1410 EXTERN_C int __fastcall HelperMethodFrameRestoreState(
1411 INDEBUG_COMMA(HelperMethodFrame *pFrame)
1416 // workhorse for our promotion efforts
1417 inline void DoPromote(promote_func *fn, ScanContext* sc, OBJECTREF *address, BOOL interior)
1419 WRAPPER_NO_CONTRACT;
1421 // We use OBJECTREF_TO_UNCHECKED_OBJECTREF since address may be an interior pointer
1423 " Promoting pointer argument at" FMT_ADDR "from" FMT_ADDR "to ",
1424 DBG_ADDR(address), DBG_ADDR(OBJECTREF_TO_UNCHECKED_OBJECTREF(*address)) ));
1427 PromoteCarefully(fn, PTR_PTR_Object(address), sc);
1429 (*fn) (PTR_PTR_Object(address), sc, 0);
1431 LOG((LF_GC, INFO3, " " FMT_ADDR "\n", DBG_ADDR(OBJECTREF_TO_UNCHECKED_OBJECTREF(*address)) ));
1435 //-----------------------------------------------------------------------------
1436 // a HelplerMethodFrames that also report additional object references
1437 //-----------------------------------------------------------------------------
1439 class HelperMethodFrame_1OBJ : public HelperMethodFrame
1441 VPTR_VTABLE_CLASS(HelperMethodFrame_1OBJ, HelperMethodFrame)
1444 #if !defined(DACCESS_COMPILE) && !defined(CROSSGEN_COMPILE)
1445 HelperMethodFrame_1OBJ(void* fCallFtnEntry, unsigned attribs, OBJECTREF* aGCPtr1)
1446 : HelperMethodFrame(fCallFtnEntry, attribs)
1448 LIMITED_METHOD_CONTRACT;
1449 gcPtrs[0] = aGCPtr1;
1450 INDEBUG(Thread::ObjectRefProtected(aGCPtr1);)
1451 INDEBUG((*aGCPtr1).Validate ();)
1455 void SetProtectedObject(PTR_OBJECTREF objPtr)
1457 LIMITED_METHOD_CONTRACT;
1459 INDEBUG(Thread::ObjectRefProtected(objPtr);)
1462 virtual void GcScanRoots(promote_func *fn, ScanContext* sc)
1464 WRAPPER_NO_CONTRACT;
1465 DoPromote(fn, sc, gcPtrs[0], FALSE);
1466 HelperMethodFrame::GcScanRoots(fn, sc);
1470 #ifndef DACCESS_COMPILE
1473 WRAPPER_NO_CONTRACT;
1474 HelperMethodFrame::Pop();
1475 Thread::ObjectRefNew(gcPtrs[0]);
1477 #endif // DACCESS_COMPILE
1479 BOOL Protects(OBJECTREF *ppORef)
1481 LIMITED_METHOD_CONTRACT;
1482 return (ppORef == gcPtrs[0]) ? TRUE : FALSE;
1488 PTR_OBJECTREF gcPtrs[1];
1490 // Keep as last entry in class
1491 DEFINE_VTABLE_GETTER_AND_CTOR_AND_DTOR(HelperMethodFrame_1OBJ)
1495 //-----------------------------------------------------------------------------
1496 // HelperMethodFrame_2OBJ
1497 //-----------------------------------------------------------------------------
1499 class HelperMethodFrame_2OBJ : public HelperMethodFrame
1501 VPTR_VTABLE_CLASS(HelperMethodFrame_2OBJ, HelperMethodFrame)
1504 #if !defined(DACCESS_COMPILE) && !defined(CROSSGEN_COMPILE)
1505 HelperMethodFrame_2OBJ(
1506 void* fCallFtnEntry,
1510 : HelperMethodFrame(fCallFtnEntry, attribs)
1512 LIMITED_METHOD_CONTRACT;
1513 gcPtrs[0] = aGCPtr1;
1514 gcPtrs[1] = aGCPtr2;
1515 INDEBUG(Thread::ObjectRefProtected(aGCPtr1);)
1516 INDEBUG(Thread::ObjectRefProtected(aGCPtr2);)
1517 INDEBUG((*aGCPtr1).Validate ();)
1518 INDEBUG((*aGCPtr2).Validate ();)
1522 virtual void GcScanRoots(promote_func *fn, ScanContext* sc)
1524 WRAPPER_NO_CONTRACT;
1525 DoPromote(fn, sc, gcPtrs[0], FALSE);
1526 DoPromote(fn, sc, gcPtrs[1], FALSE);
1527 HelperMethodFrame::GcScanRoots(fn, sc);
1531 #ifndef DACCESS_COMPILE
1534 WRAPPER_NO_CONTRACT;
1535 HelperMethodFrame::Pop();
1536 Thread::ObjectRefNew(gcPtrs[0]);
1537 Thread::ObjectRefNew(gcPtrs[1]);
1539 #endif // DACCESS_COMPILE
1541 BOOL Protects(OBJECTREF *ppORef)
1543 LIMITED_METHOD_CONTRACT;
1544 return (ppORef == gcPtrs[0] || ppORef == gcPtrs[1]) ? TRUE : FALSE;
1549 PTR_OBJECTREF gcPtrs[2];
1551 // Keep as last entry in class
1552 DEFINE_VTABLE_GETTER_AND_CTOR_AND_DTOR(HelperMethodFrame_2OBJ)
1555 //-----------------------------------------------------------------------------
1556 // HelperMethodFrame_3OBJ
1557 //-----------------------------------------------------------------------------
1559 class HelperMethodFrame_3OBJ : public HelperMethodFrame
1561 VPTR_VTABLE_CLASS(HelperMethodFrame_3OBJ, HelperMethodFrame)
1564 #if !defined(DACCESS_COMPILE) && !defined(CROSSGEN_COMPILE)
1565 HelperMethodFrame_3OBJ(
1566 void* fCallFtnEntry,
1571 : HelperMethodFrame(fCallFtnEntry, attribs)
1573 LIMITED_METHOD_CONTRACT;
1574 gcPtrs[0] = aGCPtr1;
1575 gcPtrs[1] = aGCPtr2;
1576 gcPtrs[2] = aGCPtr3;
1577 INDEBUG(Thread::ObjectRefProtected(aGCPtr1);)
1578 INDEBUG(Thread::ObjectRefProtected(aGCPtr2);)
1579 INDEBUG(Thread::ObjectRefProtected(aGCPtr3);)
1580 INDEBUG((*aGCPtr1).Validate();)
1581 INDEBUG((*aGCPtr2).Validate();)
1582 INDEBUG((*aGCPtr3).Validate();)
1586 virtual void GcScanRoots(promote_func *fn, ScanContext* sc)
1588 WRAPPER_NO_CONTRACT;
1589 DoPromote(fn, sc, gcPtrs[0], FALSE);
1590 DoPromote(fn, sc, gcPtrs[1], FALSE);
1591 DoPromote(fn, sc, gcPtrs[2], FALSE);
1592 HelperMethodFrame::GcScanRoots(fn, sc);
1596 #ifndef DACCESS_COMPILE
1599 WRAPPER_NO_CONTRACT;
1600 HelperMethodFrame::Pop();
1601 Thread::ObjectRefNew(gcPtrs[0]);
1602 Thread::ObjectRefNew(gcPtrs[1]);
1603 Thread::ObjectRefNew(gcPtrs[2]);
1605 #endif // DACCESS_COMPILE
1607 BOOL Protects(OBJECTREF *ppORef)
1609 LIMITED_METHOD_CONTRACT;
1610 return (ppORef == gcPtrs[0] || ppORef == gcPtrs[1] || ppORef == gcPtrs[2]) ? TRUE : FALSE;
1615 PTR_OBJECTREF gcPtrs[3];
1617 // Keep as last entry in class
1618 DEFINE_VTABLE_GETTER_AND_CTOR_AND_DTOR(HelperMethodFrame_3OBJ)
1622 //-----------------------------------------------------------------------------
1623 // HelperMethodFrame_PROTECTOBJ
1624 //-----------------------------------------------------------------------------
1626 class HelperMethodFrame_PROTECTOBJ : public HelperMethodFrame
1628 VPTR_VTABLE_CLASS(HelperMethodFrame_PROTECTOBJ, HelperMethodFrame)
1631 #if !defined(DACCESS_COMPILE) && !defined(CROSSGEN_COMPILE)
1632 HelperMethodFrame_PROTECTOBJ(void* fCallFtnEntry, unsigned attribs, OBJECTREF* pObjRefs, int numObjRefs)
1633 : HelperMethodFrame(fCallFtnEntry, attribs)
1635 LIMITED_METHOD_CONTRACT;
1636 m_pObjRefs = pObjRefs;
1637 m_numObjRefs = numObjRefs;
1639 for (UINT i = 0; i < m_numObjRefs; i++) {
1640 Thread::ObjectRefProtected(&m_pObjRefs[i]);
1641 m_pObjRefs[i].Validate();
1647 virtual void GcScanRoots(promote_func *fn, ScanContext* sc)
1649 WRAPPER_NO_CONTRACT;
1650 for (UINT i = 0; i < m_numObjRefs; i++) {
1651 DoPromote(fn, sc, &m_pObjRefs[i], FALSE);
1653 HelperMethodFrame::GcScanRoots(fn, sc);
1657 #ifndef DACCESS_COMPILE
1660 WRAPPER_NO_CONTRACT;
1661 HelperMethodFrame::Pop();
1662 for (UINT i = 0; i < m_numObjRefs; i++) {
1663 Thread::ObjectRefNew(&m_pObjRefs[i]);
1666 #endif // DACCESS_COMPILE
1668 BOOL Protects(OBJECTREF *ppORef)
1670 LIMITED_METHOD_CONTRACT;
1671 for (UINT i = 0; i < m_numObjRefs; i++) {
1672 if (ppORef == &m_pObjRefs[i])
1680 PTR_OBJECTREF m_pObjRefs;
1683 // Keep as last entry in class
1684 DEFINE_VTABLE_GETTER_AND_CTOR_AND_DTOR(HelperMethodFrame_PROTECTOBJ)
1687 class FramedMethodFrame : public TransitionFrame
1689 VPTR_ABSTRACT_VTABLE_CLASS(FramedMethodFrame, TransitionFrame)
1691 TADDR m_pTransitionBlock;
1694 PTR_MethodDesc m_pMD;
1697 #ifndef DACCESS_COMPILE
1698 FramedMethodFrame(TransitionBlock * pTransitionBlock, MethodDesc * pMD)
1699 : m_pTransitionBlock(dac_cast<TADDR>(pTransitionBlock)), m_pMD(pMD)
1701 LIMITED_METHOD_CONTRACT;
1703 #endif // DACCESS_COMPILE
1705 virtual TADDR GetTransitionBlock()
1707 LIMITED_METHOD_DAC_CONTRACT;
1708 return m_pTransitionBlock;
1711 virtual MethodDesc *GetFunction()
1713 LIMITED_METHOD_DAC_CONTRACT;
1717 #ifndef DACCESS_COMPILE
1718 void SetFunction(MethodDesc *pMD)
1724 MODE_COOPERATIVE; // Frame MethodDesc should be always updated in cooperative mode to avoid racing with GC stackwalk
1733 virtual ETransitionType GetTransitionType()
1735 LIMITED_METHOD_DAC_CONTRACT;
1736 return TT_M2U; // we can safely cast to a FramedMethodFrame
1741 LIMITED_METHOD_DAC_CONTRACT;
1745 #ifdef COM_STUBS_SEPARATE_FP_LOCATIONS
1746 static int GetFPArgOffset(int iArg)
1748 #ifdef _TARGET_AMD64_
1749 // Floating point spill area is between return value and transition block for frames that need it
1750 // (code:TPMethodFrame and code:ComPlusMethodFrame)
1751 return -(4 * 0x10 /* floating point args */ + 0x8 /* alignment pad */ + TransitionBlock::GetNegSpaceSize()) + (iArg * 0x10);
1757 // GetReturnObjectPtr and GetReturnValuePtr are only valid on frames
1760 PTR_PTR_Object GetReturnObjectPtr()
1762 LIMITED_METHOD_DAC_CONTRACT;
1763 return PTR_PTR_Object(GetReturnValuePtr());
1766 // Get return value address
1767 PTR_VOID GetReturnValuePtr()
1769 LIMITED_METHOD_DAC_CONTRACT;
1770 #ifdef COM_STUBS_SEPARATE_FP_LOCATIONS
1771 TADDR p = GetTransitionBlock() + GetFPArgOffset(0);
1773 TADDR p = GetTransitionBlock() - TransitionBlock::GetNegSpaceSize();
1775 // Return value is right before the transition block (or floating point spill area on AMD64) for frames that need it
1776 // (code:TPMethodFrame and code:ComPlusMethodFrame)
1777 #ifdef ENREGISTERED_RETURNTYPE_MAXSIZE
1778 p -= ENREGISTERED_RETURNTYPE_MAXSIZE;
1780 p -= sizeof(ARG_SLOT);
1782 return dac_cast<PTR_VOID>(p);
1788 LIMITED_METHOD_CONTRACT;
1792 //+----------------------------------------------------------------------------
1794 // Class: TPMethodFrame private
1796 // Synopsis: This frame is pushed onto the stack for calls on transparent
1800 //+----------------------------------------------------------------------------
1802 //------------------------------------------------------------------------
1803 // This represents a call Delegate.Invoke for secure delegate
1804 // It's only used to gc-protect the arguments during the call.
1805 // Actually the only reason to have this frame is so a proper
1806 // Assembly can be reported
1807 //------------------------------------------------------------------------
1809 class SecureDelegateFrame : public TransitionFrame
1811 VPTR_VTABLE_CLASS(SecureDelegateFrame, TransitionFrame)
1813 PTR_MethodDesc m_pMD;
1814 TransitionBlock m_TransitionBlock;
1817 virtual MethodDesc* GetFunction()
1819 LIMITED_METHOD_CONTRACT;
1823 virtual TADDR GetTransitionBlock()
1825 LIMITED_METHOD_DAC_CONTRACT;
1826 return PTR_HOST_MEMBER_TADDR(SecureDelegateFrame, this,
1830 static BYTE GetOffsetOfDatum()
1832 LIMITED_METHOD_DAC_CONTRACT;
1833 return offsetof(SecureDelegateFrame, m_pMD);
1836 static int GetOffsetOfTransitionBlock()
1838 LIMITED_METHOD_DAC_CONTRACT;
1839 return offsetof(SecureDelegateFrame, m_TransitionBlock);
1842 virtual void GcScanRoots(promote_func *fn, ScanContext* sc)
1844 WRAPPER_NO_CONTRACT;
1845 TransitionFrame::GcScanRoots(fn, sc);
1846 PromoteCallerStack(fn, sc);
1849 virtual Assembly *GetAssembly();
1853 LIMITED_METHOD_DAC_CONTRACT;
1854 return TYPE_MULTICAST;
1857 // For the debugger:
1858 // Our base class, FramedMethodFrame, is a M2U transition;
1859 // but Delegate.Invoke isn't. So override and fix it here.
1860 // If we didn't do this, we'd see a Managed/Unmanaged transition in debugger's stack trace.
1861 virtual ETransitionType GetTransitionType()
1863 LIMITED_METHOD_DAC_CONTRACT;
1867 virtual BOOL TraceFrame(Thread *thread, BOOL fromPatch,
1868 TraceDestination *trace, REGDISPLAY *regs);
1870 // Keep as last entry in class
1871 DEFINE_VTABLE_GETTER_AND_CTOR_AND_DTOR(SecureDelegateFrame)
1875 //------------------------------------------------------------------------
1876 // This represents a call Multicast.Invoke. It's only used to gc-protect
1877 // the arguments during the iteration.
1878 //------------------------------------------------------------------------
1880 class MulticastFrame : public SecureDelegateFrame
1882 VPTR_VTABLE_CLASS(MulticastFrame, SecureDelegateFrame)
1886 virtual Assembly *GetAssembly()
1888 WRAPPER_NO_CONTRACT;
1889 return Frame::GetAssembly();
1894 LIMITED_METHOD_DAC_CONTRACT;
1895 return TYPE_MULTICAST;
1898 virtual BOOL TraceFrame(Thread *thread, BOOL fromPatch,
1899 TraceDestination *trace, REGDISPLAY *regs);
1901 // Keep as last entry in class
1902 DEFINE_VTABLE_GETTER_AND_CTOR_AND_DTOR(MulticastFrame)
1906 //-----------------------------------------------------------------------
1907 // Transition frame from unmanaged to managed
1908 //-----------------------------------------------------------------------
1910 class UnmanagedToManagedFrame : public Frame
1912 friend class CheckAsmOffsets;
1914 VPTR_ABSTRACT_VTABLE_CLASS_AND_CTOR(UnmanagedToManagedFrame, Frame)
1918 // DACCESS: GetReturnAddressPtr should return the
1919 // target address of the return address in the frame.
1920 virtual TADDR GetReturnAddressPtr()
1922 LIMITED_METHOD_DAC_CONTRACT;
1923 return PTR_HOST_MEMBER_TADDR(UnmanagedToManagedFrame, this,
1927 virtual PCODE GetReturnAddress();
1929 // Retrieves pointer to the lowest-addressed argument on
1930 // the stack. Depending on the calling convention, this
1931 // may or may not be the first argument.
1932 TADDR GetPointerToArguments()
1934 LIMITED_METHOD_DAC_CONTRACT;
1935 return dac_cast<TADDR>(this) + GetOffsetOfArgs();
1938 // Exposes an offset for stub generation.
1939 static BYTE GetOffsetOfArgs()
1941 LIMITED_METHOD_DAC_CONTRACT;
1942 #if defined(_TARGET_ARM_) || defined(_TARGET_ARM64_)
1943 size_t ofs = offsetof(UnmanagedToManagedFrame, m_argumentRegisters);
1945 size_t ofs = sizeof(UnmanagedToManagedFrame);
1947 _ASSERTE(FitsInI1(ofs));
1951 // depends on the sub frames to return approp. type here
1954 LIMITED_METHOD_DAC_CONTRACT;
1958 static int GetOffsetOfDatum()
1960 LIMITED_METHOD_CONTRACT;
1961 return offsetof(UnmanagedToManagedFrame, m_pvDatum);
1965 static int GetOffsetOfCalleeSavedRegisters()
1967 LIMITED_METHOD_CONTRACT;
1968 return offsetof(UnmanagedToManagedFrame, m_calleeSavedRegisters);
1974 LIMITED_METHOD_DAC_CONTRACT;
1978 //------------------------------------------------------------------------
1979 // For the debugger.
1980 //------------------------------------------------------------------------
1981 virtual ETransitionType GetTransitionType()
1983 LIMITED_METHOD_DAC_CONTRACT;
1987 //------------------------------------------------------------------------
1988 // Performs cleanup on an exception unwind
1989 //------------------------------------------------------------------------
1990 #ifndef DACCESS_COMPILE
1991 virtual void ExceptionUnwind();
1995 TADDR m_pvDatum; // type depends on the sub class
1997 #if defined(_TARGET_X86_)
1998 CalleeSavedRegisters m_calleeSavedRegisters;
1999 TADDR m_ReturnAddress;
2000 #elif defined(_TARGET_ARM_)
2001 TADDR m_R11; // R11 chain
2002 TADDR m_ReturnAddress;
2003 ArgumentRegisters m_argumentRegisters;
2004 #elif defined (_TARGET_ARM64_)
2006 TADDR m_ReturnAddress;
2007 TADDR m_x8; // ret buff arg
2008 ArgumentRegisters m_argumentRegisters;
2010 TADDR m_ReturnAddress; // return address into unmanaged code
2014 #ifdef FEATURE_COMINTEROP
2016 //------------------------------------------------------------------------
2017 // This frame represents a transition from COM to COM+
2018 //------------------------------------------------------------------------
2020 class ComMethodFrame : public UnmanagedToManagedFrame
2022 VPTR_VTABLE_CLASS(ComMethodFrame, UnmanagedToManagedFrame)
2023 VPTR_UNIQUE(VPTR_UNIQUE_ComMethodFrame)
2028 // Return the # of stack bytes pushed by the unmanaged caller.
2029 UINT GetNumCallerStackBytes();
2032 PTR_ComCallMethodDesc GetComCallMethodDesc()
2034 LIMITED_METHOD_CONTRACT;
2035 return dac_cast<PTR_ComCallMethodDesc>(m_pvDatum);
2038 #ifndef DACCESS_COMPILE
2039 static void DoSecondPassHandlerCleanup(Frame * pCurFrame);
2040 #endif // !DACCESS_COMPILE
2043 // Keep as last entry in class
2044 DEFINE_VTABLE_GETTER_AND_CTOR_AND_DTOR(ComMethodFrame)
2047 typedef DPTR(class ComMethodFrame) PTR_ComMethodFrame;
2049 //------------------------------------------------------------------------
2050 // This represents a generic call from CLR to COM
2051 //------------------------------------------------------------------------
2053 class ComPlusMethodFrame : public FramedMethodFrame
2055 VPTR_VTABLE_CLASS(ComPlusMethodFrame, FramedMethodFrame)
2058 ComPlusMethodFrame(TransitionBlock * pTransitionBlock, MethodDesc * pMethodDesc);
2060 virtual void GcScanRoots(promote_func *fn, ScanContext* sc);
2062 virtual BOOL IsTransitionToNativeFrame()
2064 LIMITED_METHOD_CONTRACT;
2070 LIMITED_METHOD_DAC_CONTRACT;
2074 void GetUnmanagedCallSite(TADDR* ip,
2078 BOOL TraceFrame(Thread *thread, BOOL fromPatch,
2079 TraceDestination *trace, REGDISPLAY *regs);
2081 // Keep as last entry in class
2082 DEFINE_VTABLE_GETTER_AND_CTOR_AND_DTOR(ComPlusMethodFrame)
2085 #endif // FEATURE_COMINTEROP
2087 //------------------------------------------------------------------------
2088 // This represents a call from a helper to GetILStubForCalli
2089 //------------------------------------------------------------------------
2091 class PInvokeCalliFrame : public FramedMethodFrame
2093 VPTR_VTABLE_CLASS(PInvokeCalliFrame, FramedMethodFrame)
2095 PTR_VASigCookie m_pVASigCookie;
2096 PCODE m_pUnmanagedTarget;
2099 PInvokeCalliFrame(TransitionBlock * pTransitionBlock, VASigCookie * pVASigCookie, PCODE pUnmanagedTarget);
2101 virtual void GcScanRoots(promote_func *fn, ScanContext* sc)
2103 WRAPPER_NO_CONTRACT;
2104 FramedMethodFrame::GcScanRoots(fn, sc);
2105 PromoteCallerStack(fn, sc);
2108 void PromoteCallerStack(promote_func* fn, ScanContext* sc);
2111 virtual MethodDesc *GetFunction()
2113 LIMITED_METHOD_DAC_CONTRACT;
2119 LIMITED_METHOD_DAC_CONTRACT;
2120 return TYPE_INTERCEPTION;
2123 PCODE GetPInvokeCalliTarget()
2125 LIMITED_METHOD_CONTRACT;
2126 return m_pUnmanagedTarget;
2129 PTR_VASigCookie GetVASigCookie()
2131 LIMITED_METHOD_CONTRACT;
2132 return m_pVASigCookie;
2136 virtual void UpdateRegDisplay(const PREGDISPLAY);
2137 #endif // _TARGET_X86_
2139 BOOL TraceFrame(Thread *thread, BOOL fromPatch,
2140 TraceDestination *trace, REGDISPLAY *regs)
2142 WRAPPER_NO_CONTRACT;
2144 trace->InitForUnmanaged(GetPInvokeCalliTarget());
2148 // Keep as last entry in class
2149 DEFINE_VTABLE_GETTER_AND_CTOR_AND_DTOR(PInvokeCalliFrame)
2152 // Some context-related forwards.
2153 #ifdef FEATURE_HIJACK
2154 //------------------------------------------------------------------------
2155 // This frame represents a hijacked return. If we crawl back through it,
2156 // it gets us back to where the return should have gone (and eventually will
2158 //------------------------------------------------------------------------
2159 class HijackFrame : public Frame
2161 VPTR_VTABLE_CLASS(HijackFrame, Frame)
2162 VPTR_UNIQUE(VPTR_UNIQUE_HijackFrame);
2165 // DACCESS: GetReturnAddressPtr should return the
2166 // target address of the return address in the frame.
2167 virtual TADDR GetReturnAddressPtr()
2169 LIMITED_METHOD_DAC_CONTRACT;
2170 return PTR_HOST_MEMBER_TADDR(HijackFrame, this,
2174 virtual BOOL NeedsUpdateRegDisplay()
2176 LIMITED_METHOD_CONTRACT;
2180 virtual void UpdateRegDisplay(const PREGDISPLAY);
2181 virtual void GcScanRoots(promote_func *fn, ScanContext* sc);
2183 // HijackFrames are created by trip functions. See OnHijackTripThread()
2184 // They are real C++ objects on the stack.
2185 // So, it's a public function -- but that doesn't mean you should make some.
2186 HijackFrame(LPVOID returnAddress, Thread *thread, HijackArgs *args);
2190 TADDR m_ReturnAddress;
2191 PTR_Thread m_Thread;
2192 DPTR(HijackArgs) m_Args;
2194 // Keep as last entry in class
2195 DEFINE_VTABLE_GETTER_AND_CTOR_AND_DTOR(HijackFrame)
2198 #endif // FEATURE_HIJACK
2200 //------------------------------------------------------------------------
2201 // This represents a call to a method prestub. Because the prestub
2202 // can do gc and throw exceptions while building the replacement
2203 // stub, we need this frame to keep things straight.
2204 //------------------------------------------------------------------------
2206 class PrestubMethodFrame : public FramedMethodFrame
2208 VPTR_VTABLE_CLASS(PrestubMethodFrame, FramedMethodFrame)
2211 PrestubMethodFrame(TransitionBlock * pTransitionBlock, MethodDesc * pMD);
2213 virtual void GcScanRoots(promote_func *fn, ScanContext* sc)
2215 WRAPPER_NO_CONTRACT;
2216 FramedMethodFrame::GcScanRoots(fn, sc);
2217 PromoteCallerStack(fn, sc);
2220 BOOL TraceFrame(Thread *thread, BOOL fromPatch,
2221 TraceDestination *trace, REGDISPLAY *regs);
2225 LIMITED_METHOD_DAC_CONTRACT;
2226 return TYPE_INTERCEPTION;
2229 // Our base class is a a M2U TransitionType; but we're not. So override and set us back to None.
2230 ETransitionType GetTransitionType()
2232 LIMITED_METHOD_DAC_CONTRACT;
2236 Interception GetInterception();
2238 // Keep as last entry in class
2239 DEFINE_VTABLE_GETTER_AND_CTOR_AND_DTOR(PrestubMethodFrame)
2242 //------------------------------------------------------------------------
2243 // This represents a call into the virtual call stub manager
2244 // Because the stub manager can do gc and throw exceptions while
2245 // building the resolve and dispatch stubs and needs to communicate
2246 // if we need to setup for a methodDesc call or do a direct call
2247 // we need this frame to keep things straight.
2248 //------------------------------------------------------------------------
2250 class StubDispatchFrame : public FramedMethodFrame
2252 VPTR_VTABLE_CLASS(StubDispatchFrame, FramedMethodFrame)
2254 // Representative MethodTable * and slot. They are used to
2255 // compute the MethodDesc* lazily
2256 PTR_MethodTable m_pRepresentativeMT;
2257 UINT32 m_representativeSlot;
2259 // Indirection cell and containing module. Used to compute pGCRefMap lazily.
2260 PTR_Module m_pZapModule;
2261 TADDR m_pIndirection;
2263 // Cached pointer to native ref data.
2264 PTR_BYTE m_pGCRefMap;
2267 StubDispatchFrame(TransitionBlock * pTransitionBlock);
2269 MethodDesc* GetFunction();
2271 // Returns this frame GC ref map if it has one
2272 PTR_BYTE GetGCRefMap();
2275 virtual void UpdateRegDisplay(const PREGDISPLAY pRD);
2276 virtual PCODE GetReturnAddress();
2277 #endif // _TARGET_X86_
2279 PCODE GetUnadjustedReturnAddress()
2281 LIMITED_METHOD_DAC_CONTRACT;
2282 return FramedMethodFrame::GetReturnAddress();
2285 virtual void GcScanRoots(promote_func *fn, ScanContext* sc);
2287 #ifndef DACCESS_COMPILE
2288 void SetRepresentativeSlot(MethodTable * pMT, UINT32 representativeSlot)
2290 LIMITED_METHOD_CONTRACT;
2292 m_pRepresentativeMT = pMT;
2293 m_representativeSlot = representativeSlot;
2296 void SetCallSite(Module * pZapModule, TADDR pIndirection)
2298 LIMITED_METHOD_CONTRACT;
2300 m_pZapModule = pZapModule;
2301 m_pIndirection = pIndirection;
2304 void SetForNullReferenceException()
2306 LIMITED_METHOD_CONTRACT;
2308 // Nothing to do. Everything is initialized in Init.
2312 BOOL TraceFrame(Thread *thread, BOOL fromPatch,
2313 TraceDestination *trace, REGDISPLAY *regs);
2317 LIMITED_METHOD_CONTRACT;
2321 Interception GetInterception();
2324 friend class VirtualCallStubManager;
2326 // Keep as last entry in class
2327 DEFINE_VTABLE_GETTER_AND_CTOR_AND_DTOR(StubDispatchFrame)
2330 typedef VPTR(class StubDispatchFrame) PTR_StubDispatchFrame;
2333 //------------------------------------------------------------------------
2334 // This represents a call from an ExternalMethodThunk or a VirtualImportThunk
2335 // Because the resolving of the target address can do gc and/or
2336 // throw exceptions we need this frame to report the gc references.
2337 //------------------------------------------------------------------------
2339 class ExternalMethodFrame : public FramedMethodFrame
2341 VPTR_VTABLE_CLASS(ExternalMethodFrame, FramedMethodFrame)
2343 // Indirection and containing module. Used to compute pGCRefMap lazily.
2344 PTR_Module m_pZapModule;
2345 TADDR m_pIndirection;
2347 // Cached pointer to native ref data.
2348 PTR_BYTE m_pGCRefMap;
2351 ExternalMethodFrame(TransitionBlock * pTransitionBlock);
2353 virtual void GcScanRoots(promote_func *fn, ScanContext* sc);
2355 // Returns this frame GC ref map if it has one
2356 PTR_BYTE GetGCRefMap();
2358 #ifndef DACCESS_COMPILE
2359 void SetCallSite(Module * pZapModule, TADDR pIndirection)
2361 LIMITED_METHOD_CONTRACT;
2363 m_pZapModule = pZapModule;
2364 m_pIndirection = pIndirection;
2370 LIMITED_METHOD_CONTRACT;
2374 Interception GetInterception();
2377 virtual void UpdateRegDisplay(const PREGDISPLAY pRD);
2380 // Keep as last entry in class
2381 DEFINE_VTABLE_GETTER_AND_CTOR_AND_DTOR(ExternalMethodFrame)
2384 typedef VPTR(class ExternalMethodFrame) PTR_ExternalMethodFrame;
2386 #ifdef FEATURE_READYTORUN
2387 class DynamicHelperFrame : public FramedMethodFrame
2389 VPTR_VTABLE_CLASS(DynamicHelperFrame, FramedMethodFrame)
2391 int m_dynamicHelperFrameFlags;
2394 DynamicHelperFrame(TransitionBlock * pTransitionBlock, int dynamicHelperFrameFlags);
2396 virtual void GcScanRoots(promote_func *fn, ScanContext* sc);
2399 virtual void UpdateRegDisplay(const PREGDISPLAY pRD);
2402 virtual ETransitionType GetTransitionType()
2404 LIMITED_METHOD_DAC_CONTRACT;
2405 return TT_InternalCall;
2408 // Keep as last entry in class
2409 DEFINE_VTABLE_GETTER_AND_CTOR_AND_DTOR(DynamicHelperFrame)
2412 typedef VPTR(class DynamicHelperFrame) PTR_DynamicHelperFrame;
2413 #endif // FEATURE_READYTORUN
2415 //------------------------------------------------------------------------
2416 // This frame is used for instantiating stubs when the argument transform
2417 // is too complex to generate a tail-calling stub.
2418 //------------------------------------------------------------------------
2419 #if !defined(_TARGET_X86_)
2420 class StubHelperFrame : public TransitionFrame
2422 friend class CheckAsmOffsets;
2423 friend class StubLinkerCPU;
2425 VPTR_VTABLE_CLASS(StubHelperFrame, TransitionFrame)
2426 VPTR_UNIQUE(VPTR_UNIQUE_StubHelperFrame)
2428 TransitionBlock m_TransitionBlock;
2430 virtual TADDR GetTransitionBlock()
2432 LIMITED_METHOD_DAC_CONTRACT;
2433 return PTR_HOST_MEMBER_TADDR(StubHelperFrame, this,
2437 static int GetOffsetOfTransitionBlock()
2439 LIMITED_METHOD_DAC_CONTRACT;
2440 return offsetof(StubHelperFrame, m_TransitionBlock);
2444 // Keep as last entry in class
2445 DEFINE_VTABLE_GETTER_AND_CTOR_AND_DTOR(StubHelperFrame)
2447 #endif // _TARGET_X86_
2449 #ifdef FEATURE_COMINTEROP
2451 //------------------------------------------------------------------------
2452 // This represents a com to com+ call method prestub.
2453 // we need to catch exceptions etc. so this frame is not the same
2454 // as the prestub method frame
2455 // Note that in rare IJW cases, the immediate caller could be a managed method
2456 // which pinvoke-inlined a call to a COM interface, which happenned to be
2457 // implemented by a managed function via COM-interop.
2458 //------------------------------------------------------------------------
2459 class ComPrestubMethodFrame : public ComMethodFrame
2461 friend class CheckAsmOffsets;
2463 VPTR_VTABLE_CLASS(ComPrestubMethodFrame, ComMethodFrame)
2466 // Set the vptr and GSCookie
2471 LIMITED_METHOD_DAC_CONTRACT;
2472 return TYPE_INTERCEPTION;
2475 // ComPrestubMethodFrame should return the same interception type as
2476 // code:PrestubMethodFrame.GetInterception.
2477 virtual Interception GetInterception()
2479 LIMITED_METHOD_DAC_CONTRACT;
2480 return INTERCEPTION_PRESTUB;
2483 // Our base class is a a M2U TransitionType; but we're not. So override and set us back to None.
2484 virtual ETransitionType GetTransitionType()
2486 LIMITED_METHOD_DAC_CONTRACT;
2490 virtual void ExceptionUnwind()
2495 // Keep as last entry in class
2496 DEFINE_VTABLE_GETTER_AND_CTOR_AND_DTOR(ComPrestubMethodFrame)
2499 #endif // FEATURE_COMINTEROP
2502 //------------------------------------------------------------------------
2503 // This frame protects object references for the EE's convenience.
2504 // This frame type actually is created from C++.
2505 //------------------------------------------------------------------------
2506 class GCFrame : public Frame
2508 VPTR_VTABLE_CLASS(GCFrame, Frame)
2513 //--------------------------------------------------------------------
2514 // This constructor pushes a new GCFrame on the frame chain.
2515 //--------------------------------------------------------------------
2516 #ifndef DACCESS_COMPILE
2518 LIMITED_METHOD_CONTRACT;
2521 GCFrame(OBJECTREF *pObjRefs, UINT numObjRefs, BOOL maybeInterior);
2522 GCFrame(Thread *pThread, OBJECTREF *pObjRefs, UINT numObjRefs, BOOL maybeInterior);
2524 void Init(Thread *pThread, OBJECTREF *pObjRefs, UINT numObjRefs, BOOL maybeInterior);
2527 //--------------------------------------------------------------------
2528 // Pops the GCFrame and cancels the GC protection. Also
2529 // trashes the contents of pObjRef's in _DEBUG.
2530 //--------------------------------------------------------------------
2533 virtual void GcScanRoots(promote_func *fn, ScanContext* sc);
2536 virtual BOOL Protects(OBJECTREF *ppORef)
2538 LIMITED_METHOD_CONTRACT;
2539 for (UINT i = 0; i < m_numObjRefs; i++) {
2540 if (ppORef == m_pObjRefs + i) {
2548 #ifndef DACCESS_COMPILE
2549 void *operator new (size_t sz, void* p)
2551 LIMITED_METHOD_CONTRACT;
2556 #if defined(_DEBUG_IMPL)
2557 const char* GetFrameTypeName() { LIMITED_METHOD_CONTRACT; return "GCFrame"; }
2561 PTR_OBJECTREF m_pObjRefs;
2563 PTR_Thread m_pCurThread;
2564 BOOL m_MaybeInterior;
2566 // Keep as last entry in class
2567 DEFINE_VTABLE_GETTER_AND_DTOR(GCFrame)
2570 #ifdef FEATURE_INTERPRETER
2571 class InterpreterFrame: public Frame
2573 VPTR_VTABLE_CLASS(InterpreterFrame, Frame)
2575 class Interpreter* m_interp;
2579 #ifndef DACCESS_COMPILE
2580 InterpreterFrame(class Interpreter* interp);
2582 class Interpreter* GetInterpreter() { return m_interp; }
2585 virtual void GcScanRoots(promote_func *fn, ScanContext* sc);
2587 MethodDesc* GetFunction();
2590 DEFINE_VTABLE_GETTER_AND_DTOR(InterpreterFrame)
2594 typedef VPTR(class InterpreterFrame) PTR_InterpreterFrame;
2595 #endif // FEATURE_INTERPRETER
2598 //-----------------------------------------------------------------------------
2601 typedef DPTR(ByRefInfo) PTR_ByRefInfo;
2605 PTR_ByRefInfo pNext;
2608 TypeHandle typeHandle;
2612 //-----------------------------------------------------------------------------
2613 // ProtectByRefsFrame
2614 //-----------------------------------------------------------------------------
2616 class ProtectByRefsFrame : public Frame
2618 VPTR_VTABLE_CLASS(ProtectByRefsFrame, Frame)
2621 #ifndef DACCESS_COMPILE
2622 ProtectByRefsFrame(Thread *pThread, ByRefInfo *brInfo)
2625 WRAPPER_NO_CONTRACT;
2626 Frame::Push(pThread);
2630 virtual void GcScanRoots(promote_func *fn, ScanContext *sc);
2633 PTR_ByRefInfo m_brInfo;
2635 // Keep as last entry in class
2636 DEFINE_VTABLE_GETTER_AND_CTOR_AND_DTOR(ProtectByRefsFrame)
2640 //-----------------------------------------------------------------------------
2642 struct ValueClassInfo;
2643 typedef DPTR(struct ValueClassInfo) PTR_ValueClassInfo;
2645 struct ValueClassInfo
2647 PTR_ValueClassInfo pNext;
2648 PTR_MethodTable pMT;
2651 ValueClassInfo(PTR_VOID aData, PTR_MethodTable aMT, PTR_ValueClassInfo aNext)
2652 : pNext(aNext), pMT(aMT), pData(aData)
2657 //-----------------------------------------------------------------------------
2658 // ProtectValueClassFrame
2659 //-----------------------------------------------------------------------------
2662 class ProtectValueClassFrame : public Frame
2664 VPTR_VTABLE_CLASS(ProtectValueClassFrame, Frame)
2667 #ifndef DACCESS_COMPILE
2668 ProtectValueClassFrame()
2671 WRAPPER_NO_CONTRACT;
2675 ProtectValueClassFrame(Thread *pThread, ValueClassInfo *vcInfo)
2678 WRAPPER_NO_CONTRACT;
2679 Frame::Push(pThread);
2683 virtual void GcScanRoots(promote_func *fn, ScanContext *sc);
2685 ValueClassInfo ** GetValueClassInfoList()
2687 LIMITED_METHOD_CONTRACT;
2693 ValueClassInfo *m_pVCInfo;
2695 // Keep as last entry in class
2696 DEFINE_VTABLE_GETTER_AND_DTOR(ProtectValueClassFrame)
2701 BOOL IsProtectedByGCFrame(OBJECTREF *ppObjectRef);
2705 //------------------------------------------------------------------------
2706 // DebuggerClassInitMarkFrame is a small frame whose only purpose in
2707 // life is to mark for the debugger that "class initialization code" is
2708 // being run. It does nothing useful except return good values from
2709 // GetFrameType and GetInterception.
2710 //------------------------------------------------------------------------
2712 class DebuggerClassInitMarkFrame : public Frame
2714 VPTR_VTABLE_CLASS(DebuggerClassInitMarkFrame, Frame)
2718 #ifndef DACCESS_COMPILE
2719 DebuggerClassInitMarkFrame()
2721 WRAPPER_NO_CONTRACT;
2726 virtual int GetFrameType()
2728 LIMITED_METHOD_DAC_CONTRACT;
2729 return TYPE_INTERCEPTION;
2732 virtual Interception GetInterception()
2734 LIMITED_METHOD_DAC_CONTRACT;
2735 return INTERCEPTION_CLASS_INIT;
2738 // Keep as last entry in class
2739 DEFINE_VTABLE_GETTER_AND_DTOR(DebuggerClassInitMarkFrame)
2743 //------------------------------------------------------------------------
2744 // DebuggerSecurityCodeMarkFrame is a small frame whose only purpose in
2745 // life is to mark for the debugger that "security code" is
2746 // being run. It does nothing useful except return good values from
2747 // GetFrameType and GetInterception.
2748 //------------------------------------------------------------------------
2750 class DebuggerSecurityCodeMarkFrame : public Frame
2752 VPTR_VTABLE_CLASS(DebuggerSecurityCodeMarkFrame, Frame)
2755 #ifndef DACCESS_COMPILE
2756 DebuggerSecurityCodeMarkFrame()
2758 WRAPPER_NO_CONTRACT;
2763 virtual int GetFrameType()
2765 LIMITED_METHOD_DAC_CONTRACT;
2766 return TYPE_INTERCEPTION;
2769 virtual Interception GetInterception()
2771 LIMITED_METHOD_DAC_CONTRACT;
2772 return INTERCEPTION_SECURITY;
2775 // Keep as last entry in class
2776 DEFINE_VTABLE_GETTER_AND_DTOR(DebuggerSecurityCodeMarkFrame)
2779 //------------------------------------------------------------------------
2780 // DebuggerExitFrame is a small frame whose only purpose in
2781 // life is to mark for the debugger that there is an exit transiton on
2782 // the stack. This is special cased for the "break" IL instruction since
2783 // it is an fcall using a helper frame which returns TYPE_CALL instead of
2784 // an ecall (as in System.Diagnostics.Debugger.Break()) which returns
2785 // TYPE_EXIT. This just makes the two consistent for debugging services.
2786 //------------------------------------------------------------------------
2788 class DebuggerExitFrame : public Frame
2790 VPTR_VTABLE_CLASS(DebuggerExitFrame, Frame)
2793 #ifndef DACCESS_COMPILE
2796 WRAPPER_NO_CONTRACT;
2801 virtual int GetFrameType()
2803 LIMITED_METHOD_DAC_CONTRACT;
2807 // Return information about an unmanaged call the frame
2809 // ip - the unmanaged routine which will be called
2810 // returnIP - the address in the stub which the unmanaged routine
2812 // returnSP - the location returnIP is pushed onto the stack
2815 virtual void GetUnmanagedCallSite(TADDR* ip,
2819 LIMITED_METHOD_CONTRACT;
2830 // Keep as last entry in class
2831 DEFINE_VTABLE_GETTER_AND_DTOR(DebuggerExitFrame)
2834 //---------------------------------------------------------------------------------------
2836 // DebuggerU2MCatchHandlerFrame is a small frame whose only purpose in life is to mark for the debugger
2837 // that there is catch handler inside the runtime which may catch and swallow managed exceptions. The
2838 // debugger needs this frame to send a CatchHandlerFound (CHF) notification. Without this frame, the
2839 // debugger doesn't know where a managed exception is caught.
2842 // Currently this frame is only used in code:DispatchInfo.InvokeMember, which is an U2M transition.
2845 class DebuggerU2MCatchHandlerFrame : public Frame
2847 VPTR_VTABLE_CLASS(DebuggerU2MCatchHandlerFrame, Frame)
2850 #ifndef DACCESS_COMPILE
2851 DebuggerU2MCatchHandlerFrame()
2853 WRAPPER_NO_CONTRACT;
2857 DebuggerU2MCatchHandlerFrame(Thread * pThread)
2859 WRAPPER_NO_CONTRACT;
2860 Frame::Push(pThread);
2864 ETransitionType GetTransitionType()
2866 LIMITED_METHOD_DAC_CONTRACT;
2870 // Keep as last entry in class
2871 DEFINE_VTABLE_GETTER_AND_DTOR(DebuggerU2MCatchHandlerFrame)
2875 class UMThunkMarshInfo;
2876 typedef DPTR(class UMThunkMarshInfo) PTR_UMThunkMarshInfo;
2879 typedef DPTR(class UMEntryThunk) PTR_UMEntryThunk;
2881 #if defined(_TARGET_X86_)
2882 //------------------------------------------------------------------------
2883 // This frame guards an unmanaged->managed transition thru a UMThk
2884 //------------------------------------------------------------------------
2886 class UMThkCallFrame : public UnmanagedToManagedFrame
2888 VPTR_VTABLE_CLASS(UMThkCallFrame, UnmanagedToManagedFrame)
2892 #ifdef DACCESS_COMPILE
2893 virtual void EnumMemoryRegions(CLRDataEnumMemoryFlags flags);
2896 PTR_UMEntryThunk GetUMEntryThunk();
2898 static int GetOffsetOfUMEntryThunk()
2900 WRAPPER_NO_CONTRACT;
2901 return GetOffsetOfDatum();
2906 // Keep as last entry in class
2907 DEFINE_VTABLE_GETTER_AND_CTOR_AND_DTOR(UMThkCallFrame)
2909 #endif // _TARGET_X86_ && !FEATURE_PAL
2911 #if defined(_TARGET_X86_) && defined(FEATURE_COMINTEROP)
2912 //-------------------------------------------------------------------------
2913 // Exception handler for COM to managed frame
2914 // and the layout of the exception registration record structure in the stack
2915 // the layout is similar to the NT's EXCEPTIONREGISTRATION record
2916 // followed by the UnmanagedToManagedFrame specific info
2918 struct ComToManagedExRecord
2920 EXCEPTION_REGISTRATION_RECORD m_ExReg;
2921 ArgumentRegisters m_argRegs;
2922 GSCookie m_gsCookie;
2923 UMThkCallFrame m_frame;
2925 UnmanagedToManagedFrame * GetCurrFrame()
2927 LIMITED_METHOD_CONTRACT;
2931 #endif // _TARGET_X86_ && FEATURE_COMINTEROP
2934 //------------------------------------------------------------------------
2935 // This frame is pushed by any JIT'ted method that contains one or more
2936 // inlined N/Direct calls. Note that the JIT'ted method keeps it pushed
2937 // the whole time to amortize the pushing cost across the entire method.
2938 //------------------------------------------------------------------------
2940 typedef DPTR(class InlinedCallFrame) PTR_InlinedCallFrame;
2942 class InlinedCallFrame : public Frame
2944 VPTR_VTABLE_CLASS(InlinedCallFrame, Frame)
2947 virtual MethodDesc *GetFunction()
2949 WRAPPER_NO_CONTRACT;
2950 if (FrameHasActiveCall(this) && HasFunction())
2951 return PTR_MethodDesc(m_Datum);
2958 WRAPPER_NO_CONTRACT;
2961 // See code:GenericPInvokeCalliHelper
2962 return ((m_Datum != NULL) && !(dac_cast<TADDR>(m_Datum) & 0x1));
2964 return ((dac_cast<TADDR>(m_Datum) & ~0xffff) != 0);
2968 // Retrieves the return address into the code that called out
2970 virtual TADDR GetReturnAddressPtr()
2972 WRAPPER_NO_CONTRACT;
2974 if (FrameHasActiveCall(this))
2975 return PTR_HOST_MEMBER_TADDR(InlinedCallFrame, this,
2976 m_pCallerReturnAddress);
2981 virtual BOOL NeedsUpdateRegDisplay()
2983 WRAPPER_NO_CONTRACT;
2984 return FrameHasActiveCall(this);
2987 // Given a methodDesc representing an ILStub for a pinvoke call,
2988 // this method will return the MethodDesc for the actual interop
2989 // method if the current InlinedCallFrame is inactive.
2990 PTR_MethodDesc GetActualInteropMethodDesc()
2992 #if defined(_TARGET_X86_) || defined(_TARGET_ARM_)
2993 // Important: This code relies on the way JIT lays out frames. Keep it in sync
2994 // with code:Compiler.lvaAssignFrameOffsets.
2997 // +--------------------+
2998 // | lvaStubArgumentVar | <= filled with EAX in prolog |
2999 // +--------------------+ |
3001 // | InlinedCallFrame | |
3002 // | | <= m_pCrawl.pFrame | to lower addresses
3003 // +--------------------+ V
3006 // Extract the actual MethodDesc to report from the InlinedCallFrame.
3007 TADDR addr = dac_cast<TADDR>(this) + sizeof(InlinedCallFrame);
3008 return PTR_MethodDesc(*PTR_TADDR(addr));
3009 #elif defined(_WIN64)
3010 // On 64bit, the actual interop MethodDesc is saved off in a field off the InlinedCrawlFrame
3011 // which is populated by the JIT. Refer to JIT_InitPInvokeFrame for details.
3012 return PTR_MethodDesc(m_StubSecretArg);
3014 _ASSERTE(!"NYI - Interop method reporting for this architecture!");
3016 #endif // defined(_TARGET_X86_) || defined(_TARGET_ARM_)
3019 virtual void UpdateRegDisplay(const PREGDISPLAY);
3021 // m_Datum contains MethodDesc ptr or
3022 // - on AMD64: CALLI target address (if lowest bit is set)
3023 // - on X86: argument stack size (if value is <64k)
3024 // See code:HasFunction.
3025 PTR_NDirectMethodDesc m_Datum;
3028 // IL stubs fill this field with the incoming secret argument when they erect
3029 // InlinedCallFrame so we know which interop method was invoked even if the frame
3030 // is not active at the moment.
3031 PTR_VOID m_StubSecretArg;
3035 // X86: ESP after pushing the outgoing arguments, and just before calling
3036 // out to unmanaged code.
3037 // Other platforms: the field stays set throughout the declaring method.
3038 PTR_VOID m_pCallSiteSP;
3040 // EIP where the unmanaged call will return to. This will be a pointer into
3041 // the code of the managed frame which has the InlinedCallFrame
3042 // This is set to NULL in the method prolog. It gets set just before the
3043 // call to the target and reset back to NULL after the stop-for-GC check
3044 // following the call.
3045 TADDR m_pCallerReturnAddress;
3047 // This is used only for EBP. Hence, a stackwalk will miss the other
3048 // callee-saved registers for the method with the InlinedCallFrame.
3049 // To prevent GC-holes, we do not keep any GC references in callee-saved
3050 // registers across an NDirect call.
3051 TADDR m_pCalleeSavedFP;
3054 //---------------------------------------------------------------
3055 // Expose key offsets and values for stub generation.
3056 //---------------------------------------------------------------
3058 static void GetEEInfo(CORINFO_EE_INFO::InlinedCallFrameInfo * pEEInfo);
3060 // Is the specified frame an InlinedCallFrame which has an active call
3061 // inside it right now?
3062 static BOOL FrameHasActiveCall(Frame *pFrame)
3064 WRAPPER_NO_CONTRACT;
3067 pFrame != FRAME_TOP &&
3068 InlinedCallFrame::GetMethodFrameVPtr() == pFrame->GetVTablePtr() &&
3069 dac_cast<TADDR>(dac_cast<PTR_InlinedCallFrame>(pFrame)->m_pCallerReturnAddress) != NULL;
3072 // Marks the frame as inactive.
3075 m_pCallerReturnAddress = NULL;
3080 LIMITED_METHOD_DAC_CONTRACT;
3084 virtual BOOL IsTransitionToNativeFrame()
3086 LIMITED_METHOD_CONTRACT;
3090 PTR_VOID GetCallSiteSP()
3092 LIMITED_METHOD_CONTRACT;
3093 return m_pCallSiteSP;
3096 TADDR GetCalleeSavedFP()
3098 LIMITED_METHOD_DAC_CONTRACT;
3099 return m_pCalleeSavedFP;
3102 // Set the vptr and GSCookie
3105 // Keep as last entry in class
3106 DEFINE_VTABLE_GETTER_AND_CTOR_AND_DTOR(InlinedCallFrame)
3109 //------------------------------------------------------------------------
3110 // This frame is used to mark a Context/AppDomain Transition
3111 //------------------------------------------------------------------------
3113 class ContextTransitionFrame : public Frame
3116 PTR_Context m_pReturnContext;
3117 PTR_Object m_ReturnExecutionContext;
3118 PTR_Object m_LastThrownObjectInParentContext;
3119 ULONG_PTR m_LockCount; // Number of locks the thread takes
3120 // before the transition.
3121 VPTR_VTABLE_CLASS(ContextTransitionFrame, Frame)
3124 virtual void GcScanRoots(promote_func *fn, ScanContext* sc);
3126 virtual PTR_Context* GetReturnContextAddr()
3128 LIMITED_METHOD_DAC_CONTRACT;
3129 return &m_pReturnContext;
3132 virtual Object **GetReturnExecutionContextAddr()
3134 LIMITED_METHOD_CONTRACT;
3135 return (Object **) &m_ReturnExecutionContext;
3138 OBJECTREF GetLastThrownObjectInParentContext()
3140 return ObjectToOBJECTREF(m_LastThrownObjectInParentContext);
3143 void SetLastThrownObjectInParentContext(OBJECTREF lastThrownObject)
3145 m_LastThrownObjectInParentContext = OBJECTREFToObject(lastThrownObject);
3148 void SetLockCount(DWORD lockCount)
3150 LIMITED_METHOD_CONTRACT;
3151 m_LockCount = lockCount;
3153 DWORD GetLockCount()
3155 LIMITED_METHOD_CONTRACT;
3156 return (DWORD) m_LockCount;
3160 // Let debugger know that we're transitioning between AppDomains.
3161 ETransitionType GetTransitionType()
3163 LIMITED_METHOD_DAC_CONTRACT;
3164 return TT_AppDomain;
3167 #ifndef DACCESS_COMPILE
3168 ContextTransitionFrame()
3169 : m_pReturnContext(NULL)
3170 , m_ReturnExecutionContext(NULL)
3171 , m_LastThrownObjectInParentContext(NULL)
3174 LIMITED_METHOD_CONTRACT;
3178 // Keep as last entry in class
3179 DEFINE_VTABLE_GETTER_AND_DTOR(ContextTransitionFrame)
3182 // TODO [DAVBR]: For the full fix for VsWhidbey 450273, this
3183 // may be uncommented once isLegalManagedCodeCaller works properly
3184 // with non-return address inputs, and with non-DEBUG builds
3185 //bool isLegalManagedCodeCaller(TADDR retAddr);
3186 bool isRetAddr(TADDR retAddr, TADDR* whereCalled);
3188 //------------------------------------------------------------------------
3190 // This frame is used as padding for virtual stub dispatch tailcalls.
3191 // When A calls B via virtual stub dispatch, the stub dispatch stub resolves
3192 // the target code for B and jumps to it. If A wants to do a tail call,
3193 // it does not get a chance to unwind its frame since the virtual stub dispatch
3194 // stub is not set up to return the address of the target code (rather
3195 // than just jumping to it).
3196 // To do a tail call, A calls JIT_TailCall, which unwinds A's frame
3197 // and sets up a TailCallFrame. It then calls the stub dispatch stub
3198 // which disassembles the caller (JIT_TailCall, in this case) to get some information,
3199 // resolves the target code for B, and then jumps to B.
3200 // If B also does a virtual stub dispatch tail call, then we reuse the
3201 // existing TailCallFrame instead of setting up a second one.
3203 // We could eliminate TailCallFrame if we factor the VSD stub to return
3204 // the target code address. This is currently not a very important scenario
3205 // as tail calls on interface calls are uncommon.
3207 // This frame is used as padding for tailcalls which require more space
3208 // than the caller has in it's incoming argument space.
3209 // To do a tail call from A to B, A calls JIT_TailCall, which unwinds A's frame
3210 // and sets up a TailCallFrame and the arguments. It then jumps to B.
3211 // If B also does a tail call, then we reuse the
3212 // existing TailCallFrame instead of setting up a second one.
3214 // This is also used whenever value types that aren't enregisterable are
3215 // passed by value instead of ref. This is currently not a very important
3216 // scenario as tail calls are uncommon.
3218 //------------------------------------------------------------------------
3220 class TailCallFrame : public Frame
3222 VPTR_VTABLE_CLASS(TailCallFrame, Frame)
3224 #if defined(_TARGET_X86_)
3225 TADDR m_CallerAddress; // the address the tailcall was initiated from
3226 CalleeSavedRegisters m_regs; // callee saved registers - the stack walk assumes that all non-JIT frames have them
3227 TADDR m_ReturnAddress; // the return address of the tailcall
3228 #elif defined(_TARGET_AMD64_)
3230 TADDR m_padding; // code:StubLinkerCPU::CreateTailCallCopyArgsThunk expects the size of TailCallFrame to be 16-byte aligned
3231 CalleeSavedRegisters m_calleeSavedRegisters;
3232 TADDR m_ReturnAddress;
3233 #elif defined(_TARGET_ARM_)
3235 CalleeSavedRegisters m_calleeSavedRegisters;
3236 // alias saved link register as m_ReturnAddress
3238 INT32 r4, r5, r6, r7, r8, r9, r10;
3240 TADDR m_ReturnAddress;
3244 TADDR m_ReturnAddress;
3248 #ifndef CROSSGEN_COMPILE
3249 #if !defined(_TARGET_X86_)
3251 #ifndef DACCESS_COMPILE
3252 TailCallFrame(T_CONTEXT * pContext, Thread * pThread)
3254 InitFromContext(pContext);
3255 m_Next = pThread->GetFrame();
3258 void InitFromContext(T_CONTEXT * pContext);
3260 // Architecture-specific method to initialize a CONTEXT record as if the first
3261 // part of the TailCallHelperStub had executed
3262 static TailCallFrame * AdjustContextForTailCallHelperStub(_CONTEXT * pContext, size_t cbNewArgArea, Thread * pThread);
3265 static TailCallFrame * GetFrameFromContext(CONTEXT * pContext);
3266 #endif // !_TARGET_X86_
3268 #if defined(_TARGET_X86_)
3269 static TailCallFrame* FindTailCallFrame(Frame* pFrame)
3271 LIMITED_METHOD_CONTRACT;
3272 // loop through the frame chain
3273 while (pFrame->GetVTablePtr() != TailCallFrame::GetMethodFrameVPtr())
3274 pFrame = pFrame->m_Next;
3275 return (TailCallFrame*)pFrame;
3278 TADDR GetCallerAddress()
3280 LIMITED_METHOD_CONTRACT;
3281 return m_CallerAddress;
3283 #endif // _TARGET_X86_
3285 virtual TADDR GetReturnAddressPtr()
3287 LIMITED_METHOD_DAC_CONTRACT;
3288 return PTR_HOST_MEMBER_TADDR(TailCallFrame, this,
3292 virtual BOOL NeedsUpdateRegDisplay()
3297 virtual void UpdateRegDisplay(const PREGDISPLAY pRD);
3298 #endif // !CROSSGEN_COMPILE
3299 #ifdef _TARGET_AMD64_
3300 void SetGCLayout(TADDR pGCLayout)
3302 LIMITED_METHOD_CONTRACT;
3303 m_pGCLayout = pGCLayout;
3306 virtual void GcScanRoots(promote_func *fn, ScanContext* sc);
3308 void SetGCLayout(TADDR pGCLayout)
3310 LIMITED_METHOD_CONTRACT;
3311 _ASSERTE(pGCLayout == NULL);
3316 // Keep as last entry in class
3317 DEFINE_VTABLE_GETTER_AND_CTOR_AND_DTOR(TailCallFrame)
3320 //------------------------------------------------------------------------
3321 // ExceptionFilterFrame is a small frame whose only purpose in
3322 // life is to set SHADOW_SP_FILTER_DONE during unwind from exception filter.
3323 //------------------------------------------------------------------------
3325 class ExceptionFilterFrame : public Frame
3327 VPTR_VTABLE_CLASS(ExceptionFilterFrame, Frame)
3328 size_t* m_pShadowSP;
3331 #ifndef DACCESS_COMPILE
3332 ExceptionFilterFrame(size_t* pShadowSP)
3334 WRAPPER_NO_CONTRACT;
3335 m_pShadowSP = pShadowSP;
3341 // Nothing to do here.
3342 WRAPPER_NO_CONTRACT;
3347 void SetFilterDone()
3349 LIMITED_METHOD_CONTRACT;
3351 // Mark the filter as having completed
3354 // Make sure that CallJitEHFilterHelper marked us as being in the filter.
3355 _ASSERTE(*m_pShadowSP & ICodeManager::SHADOW_SP_IN_FILTER);
3356 *m_pShadowSP |= ICodeManager::SHADOW_SP_FILTER_DONE;
3362 // Keep as last entry in class
3363 DEFINE_VTABLE_GETTER_AND_CTOR_AND_DTOR(ExceptionFilterFrame)
3367 // We use IsProtectedByGCFrame to check if some OBJECTREF pointers are protected
3368 // against GC. That function doesn't know if a byref is from managed stack thus
3369 // protected by JIT. AssumeByrefFromJITStack is used to bypass that check if an
3370 // OBJECTRef pointer is passed from managed code to an FCall and it's in stack.
3371 class AssumeByrefFromJITStack : public Frame
3373 VPTR_VTABLE_CLASS(AssumeByrefFromJITStack, Frame)
3375 #ifndef DACCESS_COMPILE
3376 AssumeByrefFromJITStack(OBJECTREF *pObjRef)
3378 m_pObjRef = pObjRef;
3382 BOOL Protects(OBJECTREF *ppORef)
3384 LIMITED_METHOD_CONTRACT;
3385 return ppORef == m_pObjRef;
3389 OBJECTREF *m_pObjRef;
3391 // Keep as last entry in class
3392 DEFINE_VTABLE_GETTER_AND_DTOR(AssumeByrefFromJITStack)
3393 }; //AssumeByrefFromJITStack
3397 //-----------------------------------------------------------------------------
3398 // FrameWithCookie is used to declare a Frame in source code with a cookie
3399 // immediately preceeding it.
3400 // This is just a specialized version of GSCookieFor<T>
3402 // For Frames that are set up by stubs, the stub is responsible for setting up
3405 // Note that we have to play all these games for the GSCookie as the GSCookie
3406 // needs to precede the vtable pointer, so that the GSCookie is guaranteed to
3407 // catch any stack-buffer-overrun corruptions that overwrite the Frame data.
3409 //-----------------------------------------------------------------------------
3413 class GCSafeCollection;
3415 template <typename FrameType>
3416 class FrameWithCookie
3420 GSCookie m_gsCookie;
3426 // Overload all the required constructors
3430 m_gsCookie(GetProcessGSCookie()), m_frame() { WRAPPER_NO_CONTRACT; }
3432 FrameWithCookie(Thread * pThread) :
3433 m_gsCookie(GetProcessGSCookie()), m_frame(pThread) { WRAPPER_NO_CONTRACT; }
3435 FrameWithCookie(T_CONTEXT * pContext) :
3436 m_gsCookie(GetProcessGSCookie()), m_frame(pContext) { WRAPPER_NO_CONTRACT; }
3438 FrameWithCookie(TransitionBlock * pTransitionBlock) :
3439 m_gsCookie(GetProcessGSCookie()), m_frame(pTransitionBlock) { WRAPPER_NO_CONTRACT; }
3441 FrameWithCookie(TransitionBlock * pTransitionBlock, MethodDesc * pMD) :
3442 m_gsCookie(GetProcessGSCookie()), m_frame(pTransitionBlock, pMD) { WRAPPER_NO_CONTRACT; }
3444 FrameWithCookie(TransitionBlock * pTransitionBlock, VASigCookie * pVASigCookie, PCODE pUnmanagedTarget) :
3445 m_gsCookie(GetProcessGSCookie()), m_frame(pTransitionBlock, pVASigCookie, pUnmanagedTarget) { WRAPPER_NO_CONTRACT; }
3447 FrameWithCookie(TransitionBlock * pTransitionBlock, int frameFlags) :
3448 m_gsCookie(GetProcessGSCookie()), m_frame(pTransitionBlock, frameFlags) { WRAPPER_NO_CONTRACT; }
3452 FrameWithCookie(Thread * pThread, OBJECTREF *pObjRefs, UINT numObjRefs, BOOL maybeInterior) :
3453 m_gsCookie(GetProcessGSCookie()), m_frame(pThread, pObjRefs, numObjRefs, maybeInterior) { WRAPPER_NO_CONTRACT; }
3455 FrameWithCookie(OBJECTREF *pObjRefs, UINT numObjRefs, BOOL maybeInterior) :
3456 m_gsCookie(GetProcessGSCookie()), m_frame(pObjRefs, numObjRefs, maybeInterior) { WRAPPER_NO_CONTRACT; }
3458 // GCSafeCollectionFrame
3459 FrameWithCookie(GCSafeCollection *gcSafeCollection) :
3460 m_gsCookie(GetProcessGSCookie()), m_frame(gcSafeCollection) { WRAPPER_NO_CONTRACT; }
3462 #ifdef FEATURE_INTERPRETER
3464 FrameWithCookie(Interpreter* interp) :
3465 m_gsCookie(GetProcessGSCookie()), m_frame(interp) { WRAPPER_NO_CONTRACT; }
3469 FrameWithCookie(LPVOID returnAddress, Thread *thread, HijackArgs *args) :
3470 m_gsCookie(GetProcessGSCookie()), m_frame(returnAddress, thread, args) { WRAPPER_NO_CONTRACT; }
3472 #ifdef DEBUGGING_SUPPORTED
3474 FrameWithCookie(DebuggerEval *pDebuggerEval, TADDR returnAddress, BOOL showFrame) :
3475 m_gsCookie(GetProcessGSCookie()), m_frame(pDebuggerEval, returnAddress, showFrame) { WRAPPER_NO_CONTRACT; }
3476 #endif // DEBUGGING_SUPPORTED
3479 FrameWithCookie(T_CONTEXT * pContext, Thread *thread) :
3480 m_gsCookie(GetProcessGSCookie()), m_frame(pContext, thread) { WRAPPER_NO_CONTRACT; }
3482 #ifndef DACCESS_COMPILE
3483 // GSCookie for HelperMethodFrames is initialized in a common HelperMethodFrame init method
3485 // HelperMethodFrame
3486 FORCEINLINE FrameWithCookie(void* fCallFtnEntry, unsigned attribs = 0) :
3487 m_frame(fCallFtnEntry, attribs) { WRAPPER_NO_CONTRACT; }
3489 // HelperMethodFrame_1OBJ
3490 FORCEINLINE FrameWithCookie(void* fCallFtnEntry, unsigned attribs, OBJECTREF * aGCPtr1) :
3491 m_frame(fCallFtnEntry, attribs, aGCPtr1) { WRAPPER_NO_CONTRACT; }
3493 // HelperMethodFrame_2OBJ
3494 FORCEINLINE FrameWithCookie(void* fCallFtnEntry, unsigned attribs, OBJECTREF * aGCPtr1, OBJECTREF * aGCPtr2) :
3495 m_frame(fCallFtnEntry, attribs, aGCPtr1, aGCPtr2) { WRAPPER_NO_CONTRACT; }
3497 // HelperMethodFrame_3OBJ
3498 FORCEINLINE FrameWithCookie(void* fCallFtnEntry, unsigned attribs, OBJECTREF * aGCPtr1, OBJECTREF * aGCPtr2, OBJECTREF * aGCPtr3) :
3499 m_frame(fCallFtnEntry, attribs, aGCPtr1, aGCPtr2, aGCPtr3) { WRAPPER_NO_CONTRACT; }
3501 // HelperMethodFrame_PROTECTOBJ
3502 FORCEINLINE FrameWithCookie(void* fCallFtnEntry, unsigned attribs, OBJECTREF* pObjRefs, int numObjRefs) :
3503 m_frame(fCallFtnEntry, attribs, pObjRefs, numObjRefs) { WRAPPER_NO_CONTRACT; }
3505 #endif // DACCESS_COMPILE
3507 // ProtectByRefsFrame
3508 FrameWithCookie(Thread * pThread, ByRefInfo * pByRefs) :
3509 m_gsCookie(GetProcessGSCookie()), m_frame(pThread, pByRefs) { WRAPPER_NO_CONTRACT; }
3511 // ProtectValueClassFrame
3512 FrameWithCookie(Thread * pThread, ValueClassInfo * pValueClasses) :
3513 m_gsCookie(GetProcessGSCookie()), m_frame(pThread, pValueClasses) { WRAPPER_NO_CONTRACT; }
3515 // ExceptionFilterFrame
3516 FrameWithCookie(size_t* pShadowSP) :
3517 m_gsCookie(GetProcessGSCookie()), m_frame(pShadowSP) { WRAPPER_NO_CONTRACT; }
3520 // AssumeByrefFromJITStack
3521 FrameWithCookie(OBJECTREF *pObjRef) :
3522 m_gsCookie(GetProcessGSCookie()), m_frame(pObjRef) { WRAPPER_NO_CONTRACT; }
3524 void SetAddrOfHaveCheckedRestoreState(BOOL* pDoneCheck)
3526 WRAPPER_NO_CONTRACT;
3527 m_frame.SetAddrOfHaveCheckedRestoreState(pDoneCheck);
3533 // Overload some common Frame methods for easy redirection
3536 void Push() { WRAPPER_NO_CONTRACT; m_frame.Push(); }
3537 void Pop() { WRAPPER_NO_CONTRACT; m_frame.Pop(); }
3538 void Push(Thread * pThread) { WRAPPER_NO_CONTRACT; m_frame.Push(pThread); }
3539 void Pop(Thread * pThread) { WRAPPER_NO_CONTRACT; m_frame.Pop(pThread); }
3540 PCODE GetReturnAddress() { WRAPPER_NO_CONTRACT; return m_frame.GetReturnAddress(); }
3541 T_CONTEXT * GetContext() { WRAPPER_NO_CONTRACT; return m_frame.GetContext(); }
3542 FrameType* operator&() { LIMITED_METHOD_CONTRACT; return &m_frame; }
3543 LazyMachState * MachineState() { WRAPPER_NO_CONTRACT; return m_frame.MachineState(); }
3544 Thread * GetThread() { WRAPPER_NO_CONTRACT; return m_frame.GetThread(); }
3545 BOOL InsureInit(bool initialInit, struct MachState* unwindState)
3546 { WRAPPER_NO_CONTRACT; return m_frame.InsureInit(initialInit, unwindState); }
3547 void Poll() { WRAPPER_NO_CONTRACT; m_frame.Poll(); }
3548 void SetStackPointerPtr(TADDR sp) { WRAPPER_NO_CONTRACT; m_frame.SetStackPointerPtr(sp); }
3549 void InitAndLink(T_CONTEXT *pContext) { WRAPPER_NO_CONTRACT; m_frame.InitAndLink(pContext); }
3550 void Init(Thread *pThread, OBJECTREF *pObjRefs, UINT numObjRefs, BOOL maybeInterior)
3551 { WRAPPER_NO_CONTRACT; m_frame.Init(pThread, pObjRefs, numObjRefs, maybeInterior); }
3552 ValueClassInfo ** GetValueClassInfoList() { WRAPPER_NO_CONTRACT; return m_frame.GetValueClassInfoList(); }
3556 // Access to the underlying Frame
3557 // You should only need to use this if none of the above overloads work for you
3558 // Consider adding the required overload to the list above
3561 FrameType& operator->() { LIMITED_METHOD_CONTRACT; return m_frame; }
3564 // Since the "&" operator is overloaded, use this function to get to the
3565 // address of FrameWithCookie, rather than that of FrameWithCookie::m_frame.
3566 GSCookie * GetGSCookiePtr() { LIMITED_METHOD_CONTRACT; return &m_gsCookie; }
3569 //------------------------------------------------------------------------
3570 // These macros GC-protect OBJECTREF pointers on the EE's behalf.
3571 // In between these macros, the GC can move but not discard the protected
3572 // objects. If the GC moves an object, it will update the guarded OBJECTREF's.
3575 // OBJECTREF or = <some valid objectref>;
3576 // GCPROTECT_BEGIN(or);
3578 // ...<do work that can trigger GC>...
3583 // These macros can also protect multiple OBJECTREF's if they're packaged
3584 // into a structure:
3591 // GCPROTECT_BEGIN(gc);
3598 // - GCPROTECT_BEGININTERIOR() can be used in place of GCPROTECT_BEGIN()
3599 // to handle the case where one or more of the OBJECTREFs is potentially
3600 // an interior pointer. This is a rare situation, because boxing would
3601 // normally prevent us from encountering it. Be aware that the OBJECTREFs
3602 // we protect are not validated in this situation.
3604 // - GCPROTECT_ARRAY_BEGIN() can be used when an array of object references
3605 // is allocated on the stack. The pointer to the first element is passed
3606 // along with the number of elements in the array.
3608 // - The argument to GCPROTECT_BEGIN should be an lvalue because it
3609 // uses "sizeof" to count the OBJECTREF's.
3611 // - GCPROTECT_BEGIN spiritually violates our normal convention of not passing
3612 // non-const refernce arguments. Unfortunately, this is necessary in
3613 // order for the sizeof thing to work.
3615 // - GCPROTECT_BEGIN does _not_ zero out the OBJECTREF's. You must have
3616 // valid OBJECTREF's when you invoke this macro.
3618 // - GCPROTECT_BEGIN begins a new C nesting block. Besides allowing
3619 // GCPROTECT_BEGIN's to nest, it also has the advantage of causing
3620 // a compiler error if you forget to code a maching GCPROTECT_END.
3622 // - If you are GCPROTECTing something, it means you are expecting a GC to occur.
3623 // So we assert that GC is not forbidden. If you hit this assert, you probably need
3624 // a HELPER_METHOD_FRAME to protect the region that can cause the GC.
3625 //------------------------------------------------------------------------
3627 #ifndef DACCESS_COMPILE
3630 // Suppress prefast warning #6384: Dividing sizeof a pointer by another value
3631 #pragma warning(disable:6384)
3632 #endif /*_PREFAST_ */
3634 #define GCPROTECT_BEGIN(ObjRefStruct) do { \
3635 FrameWithCookie<GCFrame> __gcframe( \
3636 (OBJECTREF*)&(ObjRefStruct), \
3637 sizeof(ObjRefStruct)/sizeof(OBJECTREF), \
3639 /* work around unreachable code warning */ \
3640 if (true) { DEBUG_ASSURE_NO_RETURN_BEGIN(GCPROTECT)
3642 #define GCPROTECT_BEGIN_THREAD(pThread, ObjRefStruct) do { \
3643 FrameWithCookie<GCFrame> __gcframe( \
3645 (OBJECTREF*)&(ObjRefStruct), \
3646 sizeof(ObjRefStruct)/sizeof(OBJECTREF), \
3648 /* work around unreachable code warning */ \
3649 if (true) { DEBUG_ASSURE_NO_RETURN_BEGIN(GCPROTECT)
3651 #define GCPROTECT_ARRAY_BEGIN(ObjRefArray,cnt) do { \
3652 FrameWithCookie<GCFrame> __gcframe( \
3653 (OBJECTREF*)&(ObjRefArray), \
3654 cnt * sizeof(ObjRefArray) / sizeof(OBJECTREF), \
3656 /* work around unreachable code warning */ \
3657 if (true) { DEBUG_ASSURE_NO_RETURN_BEGIN(GCPROTECT)
3659 #define GCPROTECT_BEGININTERIOR(ObjRefStruct) do { \
3660 FrameWithCookie<GCFrame> __gcframe( \
3661 (OBJECTREF*)&(ObjRefStruct), \
3662 sizeof(ObjRefStruct)/sizeof(OBJECTREF), \
3664 /* work around unreachable code warning */ \
3665 if (true) { DEBUG_ASSURE_NO_RETURN_BEGIN(GCPROTECT)
3667 #define GCPROTECT_BEGININTERIOR_ARRAY(ObjRefArray,cnt) do { \
3668 FrameWithCookie<GCFrame> __gcframe( \
3669 (OBJECTREF*)&(ObjRefArray), \
3672 /* work around unreachable code warning */ \
3673 if (true) { DEBUG_ASSURE_NO_RETURN_BEGIN(GCPROTECT)
3676 #define GCPROTECT_END() \
3677 DEBUG_ASSURE_NO_RETURN_END(GCPROTECT) } \
3678 __gcframe.Pop(); } while(0)
3681 #else // #ifndef DACCESS_COMPILE
3683 #define GCPROTECT_BEGIN(ObjRefStruct)
3684 #define GCPROTECT_ARRAY_BEGIN(ObjRefArray,cnt)
3685 #define GCPROTECT_BEGININTERIOR(ObjRefStruct)
3686 #define GCPROTECT_END()
3688 #endif // #ifndef DACCESS_COMPILE
3691 #define ASSERT_ADDRESS_IN_STACK(address) _ASSERTE (Thread::IsAddressInCurrentStack (address));
3693 #if defined (_DEBUG) && !defined (DACCESS_COMPILE)
3694 #define ASSUME_BYREF_FROM_JIT_STACK_BEGIN(__objRef) \
3695 /* make sure we are only called inside an FCall */ \
3696 if (__me == 0) {}; \
3697 /* make sure the address is in stack. If the address is an interior */ \
3698 /*pointer points to GC heap, the FCall still needs to protect it explicitly */ \
3699 ASSERT_ADDRESS_IN_STACK (__objRef); \
3701 FrameWithCookie<AssumeByrefFromJITStack> __dummyAssumeByrefFromJITStack ((__objRef)); \
3702 __dummyAssumeByrefFromJITStack.Push (); \
3703 /* work around unreachable code warning */ \
3704 if (true) { DEBUG_ASSURE_NO_RETURN_BEGIN(GC_PROTECT)
3706 #define ASSUME_BYREF_FROM_JIT_STACK_END() \
3707 DEBUG_ASSURE_NO_RETURN_END(GC_PROTECT) } \
3708 __dummyAssumeByrefFromJITStack.Pop(); } while(0)
3709 #else //defined (_DEBUG) && !defined (DACCESS_COMPILE)
3710 #define ASSUME_BYREF_FROM_JIT_STACK_BEGIN(__objRef)
3711 #define ASSUME_BYREF_FROM_JIT_STACK_END()
3712 #endif //defined (_DEBUG) && !defined (DACCESS_COMPILE)
3714 //------------------------------------------------------------------------
3716 #if defined(FRAMES_TURNED_FPO_ON)
3717 #pragma optimize("", on) // Go back to command line default optimizations
3718 #undef FRAMES_TURNED_FPO_ON
3722 #endif //__frames_h__