1// Licensed to the .NET Foundation under one or more agreements.
2// The .NET Foundation licenses this file to you under the MIT license.
3// See the LICENSE file in the project root for more information.
4// FRAMES.H
5
6
7//
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.
12//
13// IMPORTANT: Since frames are not actually constructed by C++,
14// don't try to define constructor/destructor functions. They won't get
15// called.
16//
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
21// StackWalk methods.
22//
23//
24// The following is the hierarchy of frames:
25//
26// Frame - the root class. There are no actual instances
27// | of Frames.
28// |
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.
32// |
33// +- FaultingExceptionFrame - this frame was placed on a method which faulted
34// | to save additional state information
35// |
36#ifdef FEATURE_HIJACK
37// |
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.
41// |
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).
46// | |
47// | +-RedirectedThreadFrame - this frame is used for redirecting threads during suspension
48// |
49#endif // FEATURE_HIJACK
50// |
51// |
52// |
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.
56// |
57// +-HelperMethodFrame - frame used allow stack crawling inside jit helpers and fcalls
58// | |
59// + +-HelperMethodFrame_1OBJ- reports additional object references
60// | |
61// + +-HelperMethodFrame_2OBJ- reports additional object references
62// | |
63// + +-HelperMethodFrame_3OBJ- reports additional object references
64// | |
65// + +-HelperMethodFrame_PROTECTOBJ - reports additional object references
66// |
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.
71// | |
72// | +-StubHelperFrame - for instantiating stubs that need to grow stack arguments
73// | |
74// | +-SecureDelegateFrame - represents a call Delegate.Invoke for secure delegate
75// | |
76// | +-MulticastFrame - this frame protects arguments to a MulticastDelegate
77// | Invoke() call while calling each subscriber.
78// |
79// | +-FramedMethodFrame - this abstract frame represents a call to a method
80// | | that generates a full-fledged frame.
81// | |
82#ifdef FEATURE_COMINTEROP
83// | |
84// | +-ComPlusMethodFrame - represents a CLR to COM call using the generic worker
85// | |
86#endif //FEATURE_COMINTEROP
87// | |
88// | +-PInvokeCalliFrame - protects arguments when a call to GetILStubForCalli is made
89// | | to get or create IL stub for an unmanaged CALLI
90// | |
91// | +-PrestubMethodFrame - represents a call to a prestub
92// | |
93// | +-StubDispatchFrame - represents a call into the virtual call stub manager
94// | |
95// | |
96// | +-ExternalMethodFrame - represents a call from an ExternalMethdThunk
97// | |
98// | +-TPMethodFrame - for calls on transparent proxy
99// |
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.
104// | |
105#ifdef FEATURE_COMINTEROP
106// | |
107// | +-ComMethodFrame - this frame represents a transition from
108// | | com to com+
109// | |
110// | +-ComPrestubMethodFrame - prestub frame for calls from COM to CLR
111// |
112#endif //FEATURE_COMINTEROP
113#ifdef _TARGET_X86_
114// | +-UMThkCallFrame - this frame represents an unmanaged->managed
115// | transition through N/Direct
116#endif
117// |
118// +-ContextTransitionFrame - this frame is used to mark an appdomain transition
119// |
120// |
121// +-TailCallFrame - padding for tailcalls
122// |
123// +-ProtectByRefsFrame
124// |
125// +-ProtectValueClassFrame
126// |
127// +-DebuggerClassInitMarkFrame - marker frame to indicate that "class init" code is running
128// |
129// +-DebuggerSecurityCodeMarkFrame - marker frame to indicate that security code is running
130// |
131// +-DebuggerExitFrame - marker frame to indicate that a "break" IL instruction is being executed
132// |
133// +-DebuggerU2MCatchHandlerFrame - marker frame to indicate that native code is going to catch and
134// | swallow a managed exception
135// |
136#ifdef DEBUGGING_SUPPORTED
137// +-FuncEvalFrame - frame for debugger function evaluation
138#endif // DEBUGGING_SUPPORTED
139// |
140// |
141// +-ExceptionFilterFrame - this frame wraps call to exception filter
142//
143//------------------------------------------------------------------------
144#if 0
145//------------------------------------------------------------------------
146
147This is the list of Interop stubs & transition helpers with information
148regarding what (if any) Frame they used and where they were set up:
149
150P/Invoke:
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.
155
156Delegate 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).
159
160Calli:
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.
165
166ClrToCom:
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.
172
173ComToClr:
174 Normal stub:
175 Interpreted: The stub is generated by ComCall::CreateGenericComCallStub
176 (in ComToClrCall.cpp) and it erects a ComMethodFrame frame.
177Prestub:
178 The prestub is ComCallPreStub (in ComCallableWrapper.cpp) and it erects
179 a ComPrestubMethodFrame frame.
180
181Reverse P/Invoke (used for C++ exports & fixups as well as delegates
182obtained from function pointers):
183 Normal stub:
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.
188Prestub:
189 The prestub is generated by GenerateUMThunkPrestub (x86) or exists statically
190 as TheUMEntryPrestub (64-bit), and it erects an UMThkCallFrame frame.
191
192Reverse P/Invoke AppDomain selector stub:
193 The asm helper is IJWNOADThunkJumpTarget (in asmhelpers.asm) and it is frameless.
194
195//------------------------------------------------------------------------
196#endif // 0
197//------------------------------------------------------------------------
198
199#ifndef FRAME_ABSTRACT_TYPE_NAME
200#define FRAME_ABSTRACT_TYPE_NAME(frameType)
201#endif
202#ifndef FRAME_TYPE_NAME
203#define FRAME_TYPE_NAME(frameType)
204#endif
205
206FRAME_ABSTRACT_TYPE_NAME(FrameBase)
207FRAME_ABSTRACT_TYPE_NAME(Frame)
208FRAME_ABSTRACT_TYPE_NAME(TransitionFrame)
209#ifdef FEATURE_HIJACK
210FRAME_TYPE_NAME(ResumableFrame)
211FRAME_TYPE_NAME(RedirectedThreadFrame)
212#endif // FEATURE_HIJACK
213FRAME_TYPE_NAME(FaultingExceptionFrame)
214#ifdef DEBUGGING_SUPPORTED
215FRAME_TYPE_NAME(FuncEvalFrame)
216#endif // DEBUGGING_SUPPORTED
217FRAME_TYPE_NAME(HelperMethodFrame)
218FRAME_TYPE_NAME(HelperMethodFrame_1OBJ)
219FRAME_TYPE_NAME(HelperMethodFrame_2OBJ)
220FRAME_TYPE_NAME(HelperMethodFrame_3OBJ)
221FRAME_TYPE_NAME(HelperMethodFrame_PROTECTOBJ)
222FRAME_ABSTRACT_TYPE_NAME(FramedMethodFrame)
223FRAME_TYPE_NAME(SecureDelegateFrame)
224FRAME_TYPE_NAME(MulticastFrame)
225FRAME_ABSTRACT_TYPE_NAME(UnmanagedToManagedFrame)
226#ifdef FEATURE_COMINTEROP
227FRAME_TYPE_NAME(ComMethodFrame)
228FRAME_TYPE_NAME(ComPlusMethodFrame)
229FRAME_TYPE_NAME(ComPrestubMethodFrame)
230#endif // FEATURE_COMINTEROP
231FRAME_TYPE_NAME(PInvokeCalliFrame)
232#ifdef FEATURE_HIJACK
233FRAME_TYPE_NAME(HijackFrame)
234#endif // FEATURE_HIJACK
235FRAME_TYPE_NAME(PrestubMethodFrame)
236FRAME_TYPE_NAME(StubDispatchFrame)
237FRAME_TYPE_NAME(ExternalMethodFrame)
238#ifdef FEATURE_READYTORUN
239FRAME_TYPE_NAME(DynamicHelperFrame)
240#endif
241#if !defined(_TARGET_X86_)
242FRAME_TYPE_NAME(StubHelperFrame)
243#endif
244FRAME_TYPE_NAME(GCFrame)
245#ifdef FEATURE_INTERPRETER
246FRAME_TYPE_NAME(InterpreterFrame)
247#endif // FEATURE_INTERPRETER
248FRAME_TYPE_NAME(ProtectByRefsFrame)
249FRAME_TYPE_NAME(ProtectValueClassFrame)
250FRAME_TYPE_NAME(DebuggerClassInitMarkFrame)
251FRAME_TYPE_NAME(DebuggerSecurityCodeMarkFrame)
252FRAME_TYPE_NAME(DebuggerExitFrame)
253FRAME_TYPE_NAME(DebuggerU2MCatchHandlerFrame)
254#ifdef _TARGET_X86_
255FRAME_TYPE_NAME(UMThkCallFrame)
256#endif
257FRAME_TYPE_NAME(InlinedCallFrame)
258FRAME_TYPE_NAME(ContextTransitionFrame)
259FRAME_TYPE_NAME(TailCallFrame)
260FRAME_TYPE_NAME(ExceptionFilterFrame)
261#if defined(_DEBUG)
262FRAME_TYPE_NAME(AssumeByrefFromJITStack)
263#endif // _DEBUG
264
265#undef FRAME_ABSTRACT_TYPE_NAME
266#undef FRAME_TYPE_NAME
267
268//------------------------------------------------------------------------
269
270#ifndef __frames_h__
271#define __frames_h__
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
274#define FPO_ON 1
275#define FRAMES_TURNED_FPO_ON 1
276#endif
277
278#include "util.hpp"
279#include "vars.hpp"
280#include "regdisp.h"
281#include "object.h"
282#include <stddef.h>
283#include "siginfo.hpp"
284#include "method.hpp"
285#include "stackwalk.h"
286#include "stubmgr.h"
287#include "gms.h"
288#include "threads.h"
289#include "callingconvention.h"
290
291// Forward references
292class Frame;
293class FieldMarshaler;
294class FramedMethodFrame;
295typedef VPTR(class FramedMethodFrame) PTR_FramedMethodFrame;
296struct HijackArgs;
297class UMEntryThunk;
298class UMThunkMarshInfo;
299class Marshaler;
300struct ResolveCacheElem;
301#if defined(DACCESS_COMPILE)
302class DacDbiInterfaceImpl;
303#endif // DACCESS_COMPILE
304#ifdef FEATURE_COMINTEROP
305class ComMethodFrame;
306class ComCallMethodDesc;
307#endif // FEATURE_COMINTEROP
308
309// Note: the value (-1) is used to generate the largest possible pointer value: this keeps frame addresses
310// increasing upward. Because we want to ensure that we don't accidentally change this, we have a C_ASSERT
311// in stackwalk.cpp. Since it requires constant values as args, we need to define FRAME_TOP in two steps.
312// First we define FRAME_TOP_VALUE which we'll use when we do the compile-time check, then we'll define
313// FRAME_TOP in terms of FRAME_TOP_VALUE. Defining FRAME_TOP as a PTR_Frame means we don't have to type cast
314// whenever we compare it to a PTR_Frame value (the usual use of the value).
315#define FRAME_TOP_VALUE ~0 // we want to say -1 here, but gcc has trouble with the signed value
316#define FRAME_TOP (PTR_Frame(FRAME_TOP_VALUE))
317
318#ifndef DACCESS_COMPILE
319
320#if defined(FEATURE_PAL) && !defined(CROSSGEN_COMPILE)
321
322#define DEFINE_DTOR(klass) \
323 public: \
324 virtual ~klass() { PopIfChained(); }
325
326#else
327
328#define DEFINE_DTOR(klass)
329
330#endif // FEATURE_PAL && !CROSSGEN_COMPILE
331
332#define DEFINE_VTABLE_GETTER(klass) \
333 public: \
334 static TADDR GetMethodFrameVPtr() { \
335 LIMITED_METHOD_CONTRACT; \
336 klass boilerplate(false); \
337 return *((TADDR*)&boilerplate); \
338 } \
339 klass(bool dummy) { LIMITED_METHOD_CONTRACT; }
340
341#define DEFINE_VTABLE_GETTER_AND_DTOR(klass) \
342 DEFINE_VTABLE_GETTER(klass) \
343 DEFINE_DTOR(klass)
344
345#define DEFINE_VTABLE_GETTER_AND_CTOR(klass) \
346 DEFINE_VTABLE_GETTER(klass) \
347 protected: \
348 klass() { LIMITED_METHOD_CONTRACT; }
349
350#define DEFINE_VTABLE_GETTER_AND_CTOR_AND_DTOR(klass) \
351 DEFINE_VTABLE_GETTER_AND_DTOR(klass) \
352 protected: \
353 klass() { LIMITED_METHOD_CONTRACT; }
354
355#else
356
357#define DEFINE_VTABLE_GETTER(klass) \
358 public: \
359 static TADDR GetMethodFrameVPtr() { \
360 LIMITED_METHOD_CONTRACT; \
361 return klass::VPtrTargetVTable(); \
362 } \
363
364#define DEFINE_VTABLE_GETTER_AND_DTOR(klass) \
365 DEFINE_VTABLE_GETTER(klass) \
366
367#define DEFINE_VTABLE_GETTER_AND_CTOR(klass) \
368 DEFINE_VTABLE_GETTER(klass) \
369
370#define DEFINE_VTABLE_GETTER_AND_CTOR_AND_DTOR(klass) \
371 DEFINE_VTABLE_GETTER_AND_CTOR(klass) \
372
373#endif // #ifndef DACCESS_COMPILE
374
375//-----------------------------------------------------------------------------
376// For reporting on types of frames at runtime.
377class FrameTypeName
378{
379public:
380 TADDR vtbl;
381 PTR_CSTR name;
382};
383typedef DPTR(FrameTypeName) PTR_FrameTypeName;
384
385//-----------------------------------------------------------------------------
386// Frame depends on the location of its vtable within the object. This
387// superclass ensures that the vtable for Frame objects is in the same
388// location under both MSVC and GCC.
389//-----------------------------------------------------------------------------
390
391class FrameBase
392{
393 VPTR_BASE_VTABLE_CLASS(FrameBase)
394
395public:
396 FrameBase() {LIMITED_METHOD_CONTRACT; }
397
398 virtual void GcScanRoots(promote_func *fn, ScanContext* sc) {
399 LIMITED_METHOD_CONTRACT;
400 // Nothing to protect
401 }
402
403#ifdef DACCESS_COMPILE
404 virtual void EnumMemoryRegions(CLRDataEnumMemoryFlags flags) = 0;
405#endif
406};
407
408//------------------------------------------------------------------------
409// Frame defines methods common to all frame types. There are no actual
410// instances of root frames.
411//------------------------------------------------------------------------
412
413class Frame : public FrameBase
414{
415 friend class CheckAsmOffsets;
416#ifdef DACCESS_COMPILE
417 friend void Thread::EnumMemoryRegions(CLRDataEnumMemoryFlags flags);
418#endif
419
420 VPTR_ABSTRACT_VTABLE_CLASS(Frame, FrameBase)
421
422public:
423
424 //------------------------------------------------------------------------
425 // Special characteristics of a frame
426 //------------------------------------------------------------------------
427 enum FrameAttribs {
428 FRAME_ATTR_NONE = 0,
429 FRAME_ATTR_EXCEPTION = 1, // This frame caused an exception
430 FRAME_ATTR_OUT_OF_LINE = 2, // The exception out of line (IP of the frame is not correct)
431 FRAME_ATTR_FAULTED = 4, // Exception caused by Win32 fault
432 FRAME_ATTR_RESUMABLE = 8, // We may resume from this frame
433 FRAME_ATTR_CAPTURE_DEPTH_2 = 0x10, // This is a helperMethodFrame and the capture occurred at depth 2
434 FRAME_ATTR_EXACT_DEPTH = 0x20, // This is a helperMethodFrame and a jit helper, but only crawl to the given depth
435 FRAME_ATTR_NO_THREAD_ABORT = 0x40, // This is a helperMethodFrame that should not trigger thread aborts on entry
436 };
437 virtual unsigned GetFrameAttribs()
438 {
439 LIMITED_METHOD_DAC_CONTRACT;
440 return FRAME_ATTR_NONE;
441 }
442
443 //------------------------------------------------------------------------
444 // Performs cleanup on an exception unwind
445 //------------------------------------------------------------------------
446#ifndef DACCESS_COMPILE
447 virtual void ExceptionUnwind()
448 {
449 // Nothing to do here.
450 LIMITED_METHOD_CONTRACT;
451 }
452#endif
453
454 // Should be overridden to return TRUE if the frame contains register
455 // state of the caller.
456 virtual BOOL NeedsUpdateRegDisplay()
457 {
458 return FALSE;
459 }
460
461 //------------------------------------------------------------------------
462 // Is this a frame used on transition to native code from jitted code?
463 //------------------------------------------------------------------------
464 virtual BOOL IsTransitionToNativeFrame()
465 {
466 LIMITED_METHOD_CONTRACT;
467 return FALSE;
468 }
469
470 virtual MethodDesc *GetFunction()
471 {
472 LIMITED_METHOD_DAC_CONTRACT;
473 return NULL;
474 }
475
476 virtual Assembly *GetAssembly()
477 {
478 WRAPPER_NO_CONTRACT;
479 MethodDesc *pMethod = GetFunction();
480 if (pMethod != NULL)
481 return pMethod->GetModule()->GetAssembly();
482 else
483 return NULL;
484 }
485
486 // indicate the current X86 IP address within the current method
487 // return 0 if the information is not available
488 virtual PTR_BYTE GetIP()
489 {
490 LIMITED_METHOD_CONTRACT;
491 return NULL;
492 }
493
494 // DACCESS: GetReturnAddressPtr should return the
495 // target address of the return address in the frame.
496 virtual TADDR GetReturnAddressPtr()
497 {
498 LIMITED_METHOD_DAC_CONTRACT;
499 return NULL;
500 }
501
502 virtual PCODE GetReturnAddress()
503 {
504 WRAPPER_NO_CONTRACT;
505 TADDR ptr = GetReturnAddressPtr();
506 return (ptr != NULL) ? *PTR_PCODE(ptr) : NULL;
507 }
508
509 AppDomain *GetReturnDomain()
510 {
511 LIMITED_METHOD_CONTRACT;
512 return NULL;
513 }
514
515#ifndef DACCESS_COMPILE
516 virtual Object **GetReturnExecutionContextAddr()
517 {
518 LIMITED_METHOD_CONTRACT;
519 return NULL;
520 }
521
522 void SetReturnAddress(TADDR val)
523 {
524 WRAPPER_NO_CONTRACT;
525 TADDR ptr = GetReturnAddressPtr();
526 _ASSERTE(ptr != NULL);
527 *(TADDR*)ptr = val;
528 }
529#endif // #ifndef DACCESS_COMPILE
530
531 PTR_GSCookie GetGSCookiePtr()
532 {
533 WRAPPER_NO_CONTRACT;
534 return dac_cast<PTR_GSCookie>(dac_cast<TADDR>(this) + GetOffsetOfGSCookie());
535 }
536
537 static int GetOffsetOfGSCookie()
538 {
539 LIMITED_METHOD_DAC_CONTRACT;
540 return -(int)sizeof(GSCookie);
541 }
542
543 static bool HasValidVTablePtr(Frame * pFrame);
544 static PTR_GSCookie SafeGetGSCookiePtr(Frame * pFrame);
545 static void Init();
546 static void Term();
547
548 // Callers, note that the REGDISPLAY parameter is actually in/out. While
549 // UpdateRegDisplay is generally used to fill out the REGDISPLAY parameter, some
550 // overrides (e.g., code:ResumableFrame::UpdateRegDisplay) will actually READ what
551 // you pass in. So be sure to pass in a valid or zeroed out REGDISPLAY.
552 virtual void UpdateRegDisplay(const PREGDISPLAY)
553 {
554 LIMITED_METHOD_DAC_CONTRACT;
555 return;
556 }
557
558 //------------------------------------------------------------------------
559 // Debugger support
560 //------------------------------------------------------------------------
561
562
563public:
564 enum ETransitionType
565 {
566 TT_NONE,
567 TT_M2U, // we can safely cast to a FramedMethodFrame
568 TT_U2M, // we can safely cast to a UnmanagedToManagedFrame
569 TT_AppDomain, // transitioniting between AppDomains.
570 TT_InternalCall, // calling into the CLR (ecall/fcall).
571 };
572
573 // Get the type of transition.
574 // M-->U, U-->M
575 virtual ETransitionType GetTransitionType()
576 {
577 LIMITED_METHOD_DAC_CONTRACT;
578 return TT_NONE;
579 }
580
581 enum
582 {
583 TYPE_INTERNAL,
584 TYPE_ENTRY,
585 TYPE_EXIT,
586 TYPE_CONTEXT_CROSS,
587 TYPE_INTERCEPTION,
588 TYPE_SECURITY,
589 TYPE_CALL,
590 TYPE_FUNC_EVAL,
591 TYPE_MULTICAST,
592
593 // HMFs and derived classes should use this so the profiling API knows it needs
594 // to ensure HMF-specific lazy initialization gets done w/out re-entering to the host.
595 TYPE_HELPER_METHOD_FRAME,
596
597 TYPE_COUNT
598 };
599
600 virtual int GetFrameType()
601 {
602 LIMITED_METHOD_DAC_CONTRACT;
603 return TYPE_INTERNAL;
604 };
605
606 // When stepping into a method, various other methods may be called.
607 // These are refererred to as interceptors. They are all invoked
608 // with frames of various types. GetInterception() indicates whether
609 // the frame was set up for execution of such interceptors
610
611 enum Interception
612 {
613 INTERCEPTION_NONE,
614 INTERCEPTION_CLASS_INIT,
615 INTERCEPTION_EXCEPTION,
616 INTERCEPTION_CONTEXT,
617 INTERCEPTION_SECURITY,
618 INTERCEPTION_PRESTUB,
619 INTERCEPTION_OTHER,
620
621 INTERCEPTION_COUNT
622 };
623
624 virtual Interception GetInterception()
625 {
626 LIMITED_METHOD_DAC_CONTRACT;
627 return INTERCEPTION_NONE;
628 }
629
630 // Return information about an unmanaged call the frame
631 // will make.
632 // ip - the unmanaged routine which will be called
633 // returnIP - the address in the stub which the unmanaged routine
634 // will return to.
635 // returnSP - the location returnIP is pushed onto the stack
636 // during the call.
637 //
638 virtual void GetUnmanagedCallSite(TADDR* ip,
639 TADDR* returnIP,
640 TADDR* returnSP)
641 {
642 LIMITED_METHOD_CONTRACT;
643 if (ip)
644 *ip = NULL;
645
646 if (returnIP)
647 *returnIP = NULL;
648
649 if (returnSP)
650 *returnSP = NULL;
651 }
652
653 // Return where the frame will execute next - the result is filled
654 // into the given "trace" structure. The frame is responsible for
655 // detecting where it is in its execution lifetime.
656 virtual BOOL TraceFrame(Thread *thread, BOOL fromPatch,
657 TraceDestination *trace, REGDISPLAY *regs)
658 {
659 LIMITED_METHOD_CONTRACT;
660 LOG((LF_CORDB, LL_INFO10000,
661 "Default TraceFrame always returns false.\n"));
662 return FALSE;
663 }
664
665#ifdef DACCESS_COMPILE
666 virtual void EnumMemoryRegions(CLRDataEnumMemoryFlags flags)
667 {
668 WRAPPER_NO_CONTRACT;
669 DAC_ENUM_VTHIS();
670
671 // Many frames store a MethodDesc pointer in m_Datum
672 // so pick that up automatically.
673 MethodDesc* func = GetFunction();
674 if (func)
675 {
676 func->EnumMemoryRegions(flags);
677 }
678
679 // Include the NegSpace
680 GSCookie * pGSCookie = GetGSCookiePtr();
681 _ASSERTE(FitsIn<ULONG32>(PBYTE(pGSCookie) - PBYTE(this)));
682 ULONG32 negSpaceSize = static_cast<ULONG32>(PBYTE(pGSCookie) - PBYTE(this));
683 DacEnumMemoryRegion(dac_cast<TADDR>(this) - negSpaceSize, negSpaceSize);
684 }
685#endif
686
687 //---------------------------------------------------------------
688 // Expose key offsets and values for stub generation.
689 //---------------------------------------------------------------
690 static BYTE GetOffsetOfNextLink()
691 {
692 WRAPPER_NO_CONTRACT;
693 size_t ofs = offsetof(class Frame, m_Next);
694 _ASSERTE(FitsInI1(ofs));
695 return (BYTE)ofs;
696 }
697
698 // get your VTablePointer (can be used to check what type the frame is)
699 TADDR GetVTablePtr()
700 {
701 LIMITED_METHOD_DAC_CONTRACT;
702 return VPTR_HOST_VTABLE_TO_TADDR(*(LPVOID*)this);
703 }
704
705#if defined(_DEBUG) && !defined(DACCESS_COMPILE)
706 virtual BOOL Protects(OBJECTREF *ppObjectRef)
707 {
708 LIMITED_METHOD_CONTRACT;
709 return FALSE;
710 }
711#endif
712
713#ifndef DACCESS_COMPILE
714 // Link and Unlink this frame
715 VOID Push();
716 VOID Pop();
717 VOID Push(Thread *pThread);
718 VOID Pop(Thread *pThread);
719#endif // DACCESS_COMPILE
720
721#ifdef _DEBUG_IMPL
722 void Log();
723 static BOOL ShouldLogTransitions() { WRAPPER_NO_CONTRACT; return LoggingOn(LF_STUBS, LL_INFO1000000); }
724 static void __stdcall LogTransition(Frame* frame);
725 void LogFrame(int LF, int LL); // General purpose logging.
726 void LogFrameChain(int LF, int LL); // Log the whole chain.
727 virtual const char* GetFrameTypeName() {return NULL;}
728 static PTR_CSTR GetFrameTypeName(TADDR vtbl);
729#endif
730
731 //------------------------------------------------------------------------
732 // Returns the address of a security object or
733 // null if there is no space for an object on this frame.
734 //------------------------------------------------------------------------
735 virtual OBJECTREF *GetAddrOfSecurityDesc()
736 {
737 LIMITED_METHOD_CONTRACT;
738 return NULL;
739 }
740
741private:
742 // Pointer to the next frame up the stack.
743
744protected:
745 PTR_Frame m_Next; // offset +4
746
747public:
748 PTR_Frame PtrNextFrame() { return m_Next; }
749
750private:
751 // Because JIT-method activations cannot be expressed as Frames,
752 // everyone must use the StackCrawler to walk the frame chain
753 // reliably. We'll expose the Next method only to the StackCrawler
754 // to prevent mistakes.
755 /*<TODO>@NICE: Restrict "friendship" again to the StackWalker method;
756 not done because of circular dependency with threads.h</TODO>
757 */
758 // friend Frame* Thread::StackWalkFrames(PSTACKWALKFRAMESCALLBACK pCallback, VOID *pData);
759 friend class Thread;
760 friend void CrawlFrame::GotoNextFrame();
761 friend class StackFrameIterator;
762 friend class TailCallFrame;
763 friend class AppDomain;
764 friend VOID RealCOMPlusThrow(OBJECTREF
765#ifdef FEATURE_CORRUPTING_EXCEPTIONS
766 , CorruptionSeverity severity
767#endif // FEATURE_CORRUPTING_EXCEPTIONS
768 );
769 friend FCDECL0(VOID, JIT_StressGC);
770#ifdef _DEBUG
771 friend LONG WINAPI CLRVectoredExceptionHandlerShim(PEXCEPTION_POINTERS pExceptionInfo);
772#endif
773#ifdef _WIN64
774 friend Thread * __stdcall JIT_InitPInvokeFrame(InlinedCallFrame *pFrame, PTR_VOID StubSecretArg);
775#endif
776#ifdef WIN64EXCEPTIONS
777 friend class ExceptionTracker;
778#endif
779#if defined(DACCESS_COMPILE)
780 friend class DacDbiInterfaceImpl;
781#endif // DACCESS_COMPILE
782
783 PTR_Frame Next()
784 {
785 LIMITED_METHOD_DAC_CONTRACT;
786 return m_Next;
787 }
788
789protected:
790 // Frame is considered an abstract class: this protected constructor
791 // causes any attempt to instantiate one to fail at compile-time.
792 Frame()
793 : m_Next(dac_cast<PTR_Frame>(nullptr))
794 {
795 LIMITED_METHOD_CONTRACT;
796 }
797
798#if defined(FEATURE_PAL) && !defined(DACCESS_COMPILE) && !defined(CROSSGEN_COMPILE)
799 virtual ~Frame() { LIMITED_METHOD_CONTRACT; }
800
801 void PopIfChained();
802#endif // FEATURE_PAL && !DACCESS_COMPILE && !CROSSGEN_COMPILE
803};
804
805
806//-----------------------------------------------------------------------------
807// This frame provides context for a frame that
808// took an exception that is going to be resumed.
809//
810// It is necessary to create this frame if garbage
811// collection may happen during handling of the
812// exception. The FRAME_ATTR_RESUMABLE flag tells
813// the GC that the preceding frame needs to be treated
814// like the top of stack (with the important implication that
815// caller-save-regsiters will be potential roots).
816//-----------------------------------------------------------------------------
817#ifdef FEATURE_HIJACK
818//-----------------------------------------------------------------------------
819
820class ResumableFrame : public Frame
821{
822 VPTR_VTABLE_CLASS(ResumableFrame, Frame)
823
824public:
825#ifndef DACCESS_COMPILE
826 ResumableFrame(T_CONTEXT* regs) {
827 LIMITED_METHOD_CONTRACT;
828 m_Regs = regs;
829 }
830#endif
831
832 virtual TADDR GetReturnAddressPtr();
833
834 virtual BOOL NeedsUpdateRegDisplay()
835 {
836 return TRUE;
837 }
838
839 virtual void UpdateRegDisplay(const PREGDISPLAY pRD);
840
841 virtual unsigned GetFrameAttribs() {
842 LIMITED_METHOD_DAC_CONTRACT;
843 return FRAME_ATTR_RESUMABLE; // Treat the next frame as the top frame.
844 }
845
846 T_CONTEXT *GetContext() {
847 LIMITED_METHOD_DAC_CONTRACT;
848 return (m_Regs);
849 }
850
851#ifdef DACCESS_COMPILE
852 virtual void EnumMemoryRegions(CLRDataEnumMemoryFlags flags)
853 {
854 WRAPPER_NO_CONTRACT;
855 Frame::EnumMemoryRegions(flags);
856 m_Regs.EnumMem();
857 }
858#endif
859
860protected:
861 PTR_CONTEXT m_Regs;
862
863 // Keep as last entry in class
864 DEFINE_VTABLE_GETTER_AND_CTOR_AND_DTOR(ResumableFrame)
865};
866
867
868//-----------------------------------------------------------------------------
869// RedirectedThreadFrame
870//-----------------------------------------------------------------------------
871
872class RedirectedThreadFrame : public ResumableFrame
873{
874 VPTR_VTABLE_CLASS(RedirectedThreadFrame, ResumableFrame)
875 VPTR_UNIQUE(VPTR_UNIQUE_RedirectedThreadFrame)
876
877public:
878#ifndef DACCESS_COMPILE
879 RedirectedThreadFrame(T_CONTEXT *regs) : ResumableFrame(regs) {
880 LIMITED_METHOD_CONTRACT;
881 }
882
883 virtual void ExceptionUnwind();
884#endif
885
886 // Keep as last entry in class
887 DEFINE_VTABLE_GETTER_AND_CTOR_AND_DTOR(RedirectedThreadFrame)
888};
889
890typedef DPTR(RedirectedThreadFrame) PTR_RedirectedThreadFrame;
891
892inline BOOL ISREDIRECTEDTHREAD(Thread * thread)
893{
894 WRAPPER_NO_CONTRACT;
895 return (thread->GetFrame() != FRAME_TOP &&
896 thread->GetFrame()->GetVTablePtr() ==
897 RedirectedThreadFrame::GetMethodFrameVPtr());
898}
899
900inline T_CONTEXT * GETREDIRECTEDCONTEXT(Thread * thread)
901{
902 WRAPPER_NO_CONTRACT;
903 _ASSERTE(ISREDIRECTEDTHREAD(thread));
904 return dac_cast<PTR_RedirectedThreadFrame>(thread->GetFrame())->GetContext();
905}
906
907//------------------------------------------------------------------------
908#else // FEATURE_HIJACK
909//------------------------------------------------------------------------
910
911inline BOOL ISREDIRECTEDTHREAD(Thread * thread) { LIMITED_METHOD_CONTRACT; return FALSE; }
912inline CONTEXT * GETREDIRECTEDCONTEXT(Thread * thread) { LIMITED_METHOD_CONTRACT; return (CONTEXT*) NULL; }
913
914//------------------------------------------------------------------------
915#endif // FEATURE_HIJACK
916//------------------------------------------------------------------------
917// This frame represents a transition from one or more nested frameless
918// method calls to either a EE runtime helper function or a framed method.
919// Because most stackwalks from the EE start with a full-fledged frame,
920// anything but the most trivial call into the EE has to push this
921// frame in order to prevent the frameless methods inbetween from
922// getting lost.
923//------------------------------------------------------------------------
924
925class TransitionFrame : public Frame
926{
927 VPTR_ABSTRACT_VTABLE_CLASS(TransitionFrame, Frame)
928
929public:
930 virtual TADDR GetTransitionBlock() = 0;
931
932 // DACCESS: GetReturnAddressPtr should return the
933 // target address of the return address in the frame.
934 virtual TADDR GetReturnAddressPtr()
935 {
936 LIMITED_METHOD_DAC_CONTRACT;
937 return GetTransitionBlock() + TransitionBlock::GetOffsetOfReturnAddress();
938 }
939
940 //---------------------------------------------------------------
941 // Get the "this" object.
942 //---------------------------------------------------------------
943 OBJECTREF GetThis()
944 {
945 WRAPPER_NO_CONTRACT;
946 Object* obj = PTR_Object(*PTR_TADDR(GetAddrOfThis()));
947 return ObjectToOBJECTREF(obj);
948 }
949
950 PTR_OBJECTREF GetThisPtr()
951 {
952 WRAPPER_NO_CONTRACT;
953 return PTR_OBJECTREF(GetAddrOfThis());
954 }
955
956 //---------------------------------------------------------------
957 // Get the extra info for shared generic code.
958 //---------------------------------------------------------------
959 PTR_VOID GetParamTypeArg();
960
961 //---------------------------------------------------------------
962 // Gets value indicating whether the generic parameter type
963 // argument should be supressed.
964 //---------------------------------------------------------------
965 virtual BOOL SuppressParamTypeArg()
966 {
967 return FALSE;
968 }
969
970protected: // we don't want people using this directly
971 //---------------------------------------------------------------
972 // Get the address of the "this" object. WARNING!!! Whether or not "this"
973 // is gc-protected is depends on the frame type!!!
974 //---------------------------------------------------------------
975 TADDR GetAddrOfThis();
976
977public:
978 //---------------------------------------------------------------
979 // For vararg calls, return cookie.
980 //---------------------------------------------------------------
981 VASigCookie *GetVASigCookie();
982
983 CalleeSavedRegisters *GetCalleeSavedRegisters()
984 {
985 LIMITED_METHOD_DAC_CONTRACT;
986 return dac_cast<PTR_CalleeSavedRegisters>(
987 GetTransitionBlock() + TransitionBlock::GetOffsetOfCalleeSavedRegisters());
988 }
989
990 ArgumentRegisters *GetArgumentRegisters()
991 {
992 LIMITED_METHOD_DAC_CONTRACT;
993 return dac_cast<PTR_ArgumentRegisters>(
994 GetTransitionBlock() + TransitionBlock::GetOffsetOfArgumentRegisters());
995 }
996
997 TADDR GetSP()
998 {
999 LIMITED_METHOD_DAC_CONTRACT;
1000 return GetTransitionBlock() + sizeof(TransitionBlock);
1001 }
1002
1003 virtual BOOL NeedsUpdateRegDisplay()
1004 {
1005 return TRUE;
1006 }
1007
1008 virtual void UpdateRegDisplay(const PREGDISPLAY);
1009#ifdef _TARGET_X86_
1010 void UpdateRegDisplayHelper(const PREGDISPLAY, UINT cbStackPop);
1011#endif
1012
1013#if defined (_DEBUG) && !defined (DACCESS_COMPILE)
1014 virtual BOOL Protects(OBJECTREF *ppORef);
1015#endif //defined (_DEBUG) && defined (DACCESS_COMPILE)
1016
1017 // For use by classes deriving from FramedMethodFrame.
1018 void PromoteCallerStack(promote_func* fn, ScanContext* sc);
1019
1020 void PromoteCallerStackHelper(promote_func* fn, ScanContext* sc,
1021 MethodDesc * pMD, MetaSig *pmsig);
1022
1023 void PromoteCallerStackUsingGCRefMap(promote_func* fn, ScanContext* sc, PTR_BYTE pGCRefMap);
1024
1025#ifdef _TARGET_X86_
1026 UINT CbStackPopUsingGCRefMap(PTR_BYTE pGCRefMap);
1027#endif
1028
1029protected:
1030 TransitionFrame()
1031 {
1032 LIMITED_METHOD_CONTRACT;
1033 }
1034};
1035
1036//-----------------------------------------------------------------------
1037// TransitionFrames for exceptions
1038//-----------------------------------------------------------------------
1039
1040// The define USE_FEF controls how this class is used. Look for occurances
1041// of USE_FEF.
1042
1043class FaultingExceptionFrame : public Frame
1044{
1045 friend class CheckAsmOffsets;
1046
1047#ifndef WIN64EXCEPTIONS
1048#ifdef _TARGET_X86_
1049 DWORD m_Esp;
1050 CalleeSavedRegisters m_regs;
1051 TADDR m_ReturnAddress;
1052#else // _TARGET_X86_
1053 #error "Unsupported architecture"
1054#endif // _TARGET_X86_
1055#else // WIN64EXCEPTIONS
1056 BOOL m_fFilterExecuted; // Flag for FirstCallToHandler
1057 TADDR m_ReturnAddress;
1058 T_CONTEXT m_ctx;
1059#endif // !WIN64EXCEPTIONS
1060
1061 VPTR_VTABLE_CLASS(FaultingExceptionFrame, Frame)
1062
1063public:
1064#ifndef DACCESS_COMPILE
1065 FaultingExceptionFrame() {
1066 LIMITED_METHOD_CONTRACT;
1067 }
1068#endif
1069
1070 virtual TADDR GetReturnAddressPtr()
1071 {
1072 LIMITED_METHOD_DAC_CONTRACT;
1073 return PTR_HOST_MEMBER_TADDR(FaultingExceptionFrame, this, m_ReturnAddress);
1074 }
1075
1076 void Init(T_CONTEXT *pContext);
1077 void InitAndLink(T_CONTEXT *pContext);
1078
1079 Interception GetInterception()
1080 {
1081 LIMITED_METHOD_DAC_CONTRACT;
1082 return INTERCEPTION_EXCEPTION;
1083 }
1084
1085 unsigned GetFrameAttribs()
1086 {
1087 LIMITED_METHOD_DAC_CONTRACT;
1088 return FRAME_ATTR_EXCEPTION | FRAME_ATTR_FAULTED;
1089 }
1090
1091#ifndef WIN64EXCEPTIONS
1092 CalleeSavedRegisters *GetCalleeSavedRegisters()
1093 {
1094#ifdef _TARGET_X86_
1095 LIMITED_METHOD_DAC_CONTRACT;
1096 return &m_regs;
1097#else
1098 PORTABILITY_ASSERT("GetCalleeSavedRegisters");
1099#endif // _TARGET_X86_
1100 }
1101#endif // WIN64EXCEPTIONS
1102
1103#ifdef WIN64EXCEPTIONS
1104 T_CONTEXT *GetExceptionContext ()
1105 {
1106 LIMITED_METHOD_CONTRACT;
1107 return &m_ctx;
1108 }
1109
1110 BOOL * GetFilterExecutedFlag()
1111 {
1112 LIMITED_METHOD_CONTRACT;
1113 return &m_fFilterExecuted;
1114 }
1115#endif // WIN64EXCEPTIONS
1116
1117 virtual BOOL NeedsUpdateRegDisplay()
1118 {
1119 return TRUE;
1120 }
1121
1122 virtual void UpdateRegDisplay(const PREGDISPLAY);
1123
1124 // Keep as last entry in class
1125 DEFINE_VTABLE_GETTER_AND_DTOR(FaultingExceptionFrame)
1126};
1127
1128//-----------------------------------------------------------------------
1129// Frame for debugger function evaluation
1130//
1131// This frame holds a ptr to a DebuggerEval object which contains a copy
1132// of the thread's context at the time it was hijacked for the func
1133// eval.
1134//
1135// UpdateRegDisplay updates all registers inthe REGDISPLAY, not just
1136// the callee saved registers, because we can hijack for a func eval
1137// at any point in a thread's execution.
1138//
1139//-----------------------------------------------------------------------
1140
1141#ifdef DEBUGGING_SUPPORTED
1142class DebuggerEval;
1143typedef DPTR(class DebuggerEval) PTR_DebuggerEval;
1144
1145class FuncEvalFrame : public Frame
1146{
1147 VPTR_VTABLE_CLASS(FuncEvalFrame, Frame)
1148
1149 TADDR m_ReturnAddress;
1150 PTR_DebuggerEval m_pDebuggerEval;
1151
1152 BOOL m_showFrame;
1153
1154public:
1155#ifndef DACCESS_COMPILE
1156 FuncEvalFrame(DebuggerEval *pDebuggerEval, TADDR returnAddress, BOOL showFrame)
1157 {
1158 LIMITED_METHOD_CONTRACT;
1159 m_pDebuggerEval = pDebuggerEval;
1160 m_ReturnAddress = returnAddress;
1161 m_showFrame = showFrame;
1162 }
1163#endif
1164
1165 virtual BOOL IsTransitionToNativeFrame()
1166 {
1167 LIMITED_METHOD_CONTRACT;
1168 return FALSE;
1169 }
1170
1171 virtual int GetFrameType()
1172 {
1173 LIMITED_METHOD_DAC_CONTRACT;
1174 return TYPE_FUNC_EVAL;
1175 }
1176
1177 virtual unsigned GetFrameAttribs();
1178
1179 virtual BOOL NeedsUpdateRegDisplay()
1180 {
1181 return TRUE;
1182 }
1183
1184 virtual void UpdateRegDisplay(const PREGDISPLAY);
1185
1186 virtual DebuggerEval * GetDebuggerEval();
1187
1188 virtual TADDR GetReturnAddressPtr();
1189
1190 /*
1191 * ShowFrame
1192 *
1193 * Returns if this frame should be returned as part of a stack trace to a debugger or not.
1194 *
1195 */
1196 BOOL ShowFrame()
1197 {
1198 LIMITED_METHOD_CONTRACT;
1199
1200 return m_showFrame;
1201 }
1202
1203 // Keep as last entry in class
1204 DEFINE_VTABLE_GETTER_AND_CTOR_AND_DTOR(FuncEvalFrame)
1205};
1206
1207typedef VPTR(FuncEvalFrame) PTR_FuncEvalFrame;
1208#endif // DEBUGGING_SUPPORTED
1209
1210//----------------------------------------------------------------------------------------------
1211// A HelperMethodFrame is created by jit helper (Modified slightly it could be used
1212// for native routines). This frame just does the callee saved register fixup.
1213// It does NOT protect arguments; you must use GCPROTECT or one of the HelperMethodFrame
1214// subclases. (see JitInterface for sample use, YOU CAN'T RETURN WHILE IN THE PROTECTED STATE!)
1215//----------------------------------------------------------------------------------------------
1216
1217class HelperMethodFrame : public Frame
1218{
1219 VPTR_VTABLE_CLASS(HelperMethodFrame, Frame);
1220
1221public:
1222#ifndef DACCESS_COMPILE
1223 // Lazy initialization of HelperMethodFrame. Need to
1224 // call InsureInit to complete initialization
1225 // If this is an FCall, the first param is the entry point for the FCALL.
1226 // The MethodDesc will be looked up form this (lazily), and this method
1227 // will be used in stack reporting, if this is not an FCall pass a 0
1228 FORCEINLINE HelperMethodFrame(void* fCallFtnEntry, unsigned attribs = 0)
1229 {
1230 WRAPPER_NO_CONTRACT;
1231 // Most of the initialization is actually done in HelperMethodFrame::Push()
1232 INDEBUG(memset(&m_Attribs, 0xCC, sizeof(HelperMethodFrame) - offsetof(HelperMethodFrame, m_Attribs));)
1233 m_Attribs = attribs;
1234 m_FCallEntry = (TADDR)fCallFtnEntry;
1235 }
1236#endif // DACCESS_COMPILE
1237
1238 virtual int GetFrameType()
1239 {
1240 LIMITED_METHOD_DAC_CONTRACT;
1241 return TYPE_HELPER_METHOD_FRAME;
1242 };
1243
1244 virtual PCODE GetReturnAddress()
1245 {
1246 LIMITED_METHOD_DAC_CONTRACT;
1247
1248 if (!m_MachState.isValid())
1249 {
1250#if defined(DACCESS_COMPILE)
1251 MachState unwoundState;
1252 InsureInit(false, &unwoundState);
1253 return unwoundState.GetRetAddr();
1254#else // !DACCESS_COMPILE
1255 _ASSERTE(!"HMF's should always be initialized in the non-DAC world.");
1256 return NULL;
1257
1258#endif // !DACCESS_COMPILE
1259 }
1260
1261 return m_MachState.GetRetAddr();
1262 }
1263
1264 virtual MethodDesc* GetFunction();
1265
1266 virtual BOOL NeedsUpdateRegDisplay()
1267 {
1268 return TRUE;
1269 }
1270
1271 virtual void UpdateRegDisplay(const PREGDISPLAY);
1272
1273 virtual Interception GetInterception()
1274 {
1275 WRAPPER_NO_CONTRACT;
1276 LIMITED_METHOD_DAC_CONTRACT;
1277 if (GetFrameAttribs() & FRAME_ATTR_EXCEPTION)
1278 return(INTERCEPTION_EXCEPTION);
1279 return(INTERCEPTION_NONE);
1280 }
1281
1282 virtual ETransitionType GetTransitionType()
1283 {
1284 LIMITED_METHOD_DAC_CONTRACT;
1285 return TT_InternalCall;
1286 }
1287
1288#ifdef _DEBUG
1289 void SetAddrOfHaveCheckedRestoreState(BOOL* pDoneCheck)
1290 {
1291 m_pDoneCheck = pDoneCheck;
1292 }
1293
1294 BOOL HaveDoneConfirmStateCheck()
1295 {
1296 LIMITED_METHOD_CONTRACT;
1297 _ASSERTE(m_pDoneCheck != NULL);
1298 return *m_pDoneCheck;
1299 }
1300
1301 void SetHaveDoneConfirmStateCheck()
1302 {
1303 LIMITED_METHOD_CONTRACT;
1304 _ASSERTE(m_pDoneCheck != NULL);
1305 *m_pDoneCheck = TRUE;
1306 }
1307#endif
1308
1309 virtual unsigned GetFrameAttribs()
1310 {
1311 LIMITED_METHOD_DAC_CONTRACT;
1312 return(m_Attribs);
1313 }
1314
1315#ifdef DACCESS_COMPILE
1316 virtual void EnumMemoryRegions(CLRDataEnumMemoryFlags flags)
1317 {
1318 WRAPPER_NO_CONTRACT;
1319 Frame::EnumMemoryRegions(flags);
1320 }
1321#endif
1322
1323#ifndef DACCESS_COMPILE
1324 void Push();
1325 void Pop();
1326
1327 FORCEINLINE void Poll()
1328 {
1329 WRAPPER_NO_CONTRACT;
1330 if (m_pThread->CatchAtSafePointOpportunistic())
1331 CommonTripThread();
1332 }
1333#endif // DACCESS_COMPILE
1334
1335 BOOL InsureInit(bool initialInit, struct MachState* unwindState, HostCallPreference hostCallPreference = AllowHostCalls);
1336
1337 LazyMachState * MachineState() {
1338 LIMITED_METHOD_CONTRACT;
1339 return &m_MachState;
1340 }
1341
1342 Thread * GetThread() {
1343 LIMITED_METHOD_CONTRACT;
1344 return m_pThread;
1345 }
1346
1347private:
1348 // Slow paths of Push/Pop are factored into a separate functions for better perf.
1349 NOINLINE void PushSlowHelper();
1350 NOINLINE void PopSlowHelper();
1351
1352protected:
1353 PTR_MethodDesc m_pMD;
1354 unsigned m_Attribs;
1355 INDEBUG(BOOL* m_pDoneCheck;)
1356 PTR_Thread m_pThread;
1357 TADDR m_FCallEntry; // used to determine our identity for stack traces
1358
1359 LazyMachState m_MachState; // pRetAddr points to the return address and the stack arguments
1360
1361 // Keep as last entry in class
1362 DEFINE_VTABLE_GETTER_AND_CTOR_AND_DTOR(HelperMethodFrame)
1363};
1364
1365// Restores registers saved in m_MachState
1366EXTERN_C int __fastcall HelperMethodFrameRestoreState(
1367 INDEBUG_COMMA(HelperMethodFrame *pFrame)
1368 MachState *pState
1369 );
1370
1371
1372// workhorse for our promotion efforts
1373inline void DoPromote(promote_func *fn, ScanContext* sc, OBJECTREF *address, BOOL interior)
1374{
1375 WRAPPER_NO_CONTRACT;
1376
1377 // We use OBJECTREF_TO_UNCHECKED_OBJECTREF since address may be an interior pointer
1378 LOG((LF_GC, INFO3,
1379 " Promoting pointer argument at" FMT_ADDR "from" FMT_ADDR "to ",
1380 DBG_ADDR(address), DBG_ADDR(OBJECTREF_TO_UNCHECKED_OBJECTREF(*address)) ));
1381
1382 if (interior)
1383 PromoteCarefully(fn, PTR_PTR_Object(address), sc);
1384 else
1385 (*fn) (PTR_PTR_Object(address), sc, 0);
1386
1387 LOG((LF_GC, INFO3, " " FMT_ADDR "\n", DBG_ADDR(OBJECTREF_TO_UNCHECKED_OBJECTREF(*address)) ));
1388}
1389
1390
1391//-----------------------------------------------------------------------------
1392// a HelplerMethodFrames that also report additional object references
1393//-----------------------------------------------------------------------------
1394
1395class HelperMethodFrame_1OBJ : public HelperMethodFrame
1396{
1397 VPTR_VTABLE_CLASS(HelperMethodFrame_1OBJ, HelperMethodFrame)
1398
1399public:
1400#if !defined(DACCESS_COMPILE) && !defined(CROSSGEN_COMPILE)
1401 HelperMethodFrame_1OBJ(void* fCallFtnEntry, unsigned attribs, OBJECTREF* aGCPtr1)
1402 : HelperMethodFrame(fCallFtnEntry, attribs)
1403 {
1404 LIMITED_METHOD_CONTRACT;
1405 gcPtrs[0] = aGCPtr1;
1406 INDEBUG(Thread::ObjectRefProtected(aGCPtr1);)
1407 INDEBUG((*aGCPtr1).Validate ();)
1408 }
1409#endif
1410
1411 void SetProtectedObject(PTR_OBJECTREF objPtr)
1412 {
1413 LIMITED_METHOD_CONTRACT;
1414 gcPtrs[0] = objPtr;
1415 INDEBUG(Thread::ObjectRefProtected(objPtr);)
1416 }
1417
1418 virtual void GcScanRoots(promote_func *fn, ScanContext* sc)
1419 {
1420 WRAPPER_NO_CONTRACT;
1421 DoPromote(fn, sc, gcPtrs[0], FALSE);
1422 HelperMethodFrame::GcScanRoots(fn, sc);
1423 }
1424
1425#ifdef _DEBUG
1426#ifndef DACCESS_COMPILE
1427 void Pop()
1428 {
1429 WRAPPER_NO_CONTRACT;
1430 HelperMethodFrame::Pop();
1431 Thread::ObjectRefNew(gcPtrs[0]);
1432 }
1433#endif // DACCESS_COMPILE
1434
1435 BOOL Protects(OBJECTREF *ppORef)
1436 {
1437 LIMITED_METHOD_CONTRACT;
1438 return (ppORef == gcPtrs[0]) ? TRUE : FALSE;
1439 }
1440
1441#endif
1442
1443private:
1444 PTR_OBJECTREF gcPtrs[1];
1445
1446 // Keep as last entry in class
1447 DEFINE_VTABLE_GETTER_AND_CTOR_AND_DTOR(HelperMethodFrame_1OBJ)
1448};
1449
1450
1451//-----------------------------------------------------------------------------
1452// HelperMethodFrame_2OBJ
1453//-----------------------------------------------------------------------------
1454
1455class HelperMethodFrame_2OBJ : public HelperMethodFrame
1456{
1457 VPTR_VTABLE_CLASS(HelperMethodFrame_2OBJ, HelperMethodFrame)
1458
1459public:
1460#if !defined(DACCESS_COMPILE) && !defined(CROSSGEN_COMPILE)
1461 HelperMethodFrame_2OBJ(
1462 void* fCallFtnEntry,
1463 unsigned attribs,
1464 OBJECTREF* aGCPtr1,
1465 OBJECTREF* aGCPtr2)
1466 : HelperMethodFrame(fCallFtnEntry, attribs)
1467 {
1468 LIMITED_METHOD_CONTRACT;
1469 gcPtrs[0] = aGCPtr1;
1470 gcPtrs[1] = aGCPtr2;
1471 INDEBUG(Thread::ObjectRefProtected(aGCPtr1);)
1472 INDEBUG(Thread::ObjectRefProtected(aGCPtr2);)
1473 INDEBUG((*aGCPtr1).Validate ();)
1474 INDEBUG((*aGCPtr2).Validate ();)
1475 }
1476#endif
1477
1478 virtual void GcScanRoots(promote_func *fn, ScanContext* sc)
1479 {
1480 WRAPPER_NO_CONTRACT;
1481 DoPromote(fn, sc, gcPtrs[0], FALSE);
1482 DoPromote(fn, sc, gcPtrs[1], FALSE);
1483 HelperMethodFrame::GcScanRoots(fn, sc);
1484 }
1485
1486#ifdef _DEBUG
1487#ifndef DACCESS_COMPILE
1488 void Pop()
1489 {
1490 WRAPPER_NO_CONTRACT;
1491 HelperMethodFrame::Pop();
1492 Thread::ObjectRefNew(gcPtrs[0]);
1493 Thread::ObjectRefNew(gcPtrs[1]);
1494 }
1495#endif // DACCESS_COMPILE
1496
1497 BOOL Protects(OBJECTREF *ppORef)
1498 {
1499 LIMITED_METHOD_CONTRACT;
1500 return (ppORef == gcPtrs[0] || ppORef == gcPtrs[1]) ? TRUE : FALSE;
1501 }
1502#endif
1503
1504private:
1505 PTR_OBJECTREF gcPtrs[2];
1506
1507 // Keep as last entry in class
1508 DEFINE_VTABLE_GETTER_AND_CTOR_AND_DTOR(HelperMethodFrame_2OBJ)
1509};
1510
1511//-----------------------------------------------------------------------------
1512// HelperMethodFrame_3OBJ
1513//-----------------------------------------------------------------------------
1514
1515class HelperMethodFrame_3OBJ : public HelperMethodFrame
1516{
1517 VPTR_VTABLE_CLASS(HelperMethodFrame_3OBJ, HelperMethodFrame)
1518
1519public:
1520#if !defined(DACCESS_COMPILE) && !defined(CROSSGEN_COMPILE)
1521 HelperMethodFrame_3OBJ(
1522 void* fCallFtnEntry,
1523 unsigned attribs,
1524 OBJECTREF* aGCPtr1,
1525 OBJECTREF* aGCPtr2,
1526 OBJECTREF* aGCPtr3)
1527 : HelperMethodFrame(fCallFtnEntry, attribs)
1528 {
1529 LIMITED_METHOD_CONTRACT;
1530 gcPtrs[0] = aGCPtr1;
1531 gcPtrs[1] = aGCPtr2;
1532 gcPtrs[2] = aGCPtr3;
1533 INDEBUG(Thread::ObjectRefProtected(aGCPtr1);)
1534 INDEBUG(Thread::ObjectRefProtected(aGCPtr2);)
1535 INDEBUG(Thread::ObjectRefProtected(aGCPtr3);)
1536 INDEBUG((*aGCPtr1).Validate();)
1537 INDEBUG((*aGCPtr2).Validate();)
1538 INDEBUG((*aGCPtr3).Validate();)
1539 }
1540#endif
1541
1542 virtual void GcScanRoots(promote_func *fn, ScanContext* sc)
1543 {
1544 WRAPPER_NO_CONTRACT;
1545 DoPromote(fn, sc, gcPtrs[0], FALSE);
1546 DoPromote(fn, sc, gcPtrs[1], FALSE);
1547 DoPromote(fn, sc, gcPtrs[2], FALSE);
1548 HelperMethodFrame::GcScanRoots(fn, sc);
1549 }
1550
1551#ifdef _DEBUG
1552#ifndef DACCESS_COMPILE
1553 void Pop()
1554 {
1555 WRAPPER_NO_CONTRACT;
1556 HelperMethodFrame::Pop();
1557 Thread::ObjectRefNew(gcPtrs[0]);
1558 Thread::ObjectRefNew(gcPtrs[1]);
1559 Thread::ObjectRefNew(gcPtrs[2]);
1560 }
1561#endif // DACCESS_COMPILE
1562
1563 BOOL Protects(OBJECTREF *ppORef)
1564 {
1565 LIMITED_METHOD_CONTRACT;
1566 return (ppORef == gcPtrs[0] || ppORef == gcPtrs[1] || ppORef == gcPtrs[2]) ? TRUE : FALSE;
1567 }
1568#endif
1569
1570private:
1571 PTR_OBJECTREF gcPtrs[3];
1572
1573 // Keep as last entry in class
1574 DEFINE_VTABLE_GETTER_AND_CTOR_AND_DTOR(HelperMethodFrame_3OBJ)
1575};
1576
1577
1578//-----------------------------------------------------------------------------
1579// HelperMethodFrame_PROTECTOBJ
1580//-----------------------------------------------------------------------------
1581
1582class HelperMethodFrame_PROTECTOBJ : public HelperMethodFrame
1583{
1584 VPTR_VTABLE_CLASS(HelperMethodFrame_PROTECTOBJ, HelperMethodFrame)
1585
1586public:
1587#if !defined(DACCESS_COMPILE) && !defined(CROSSGEN_COMPILE)
1588 HelperMethodFrame_PROTECTOBJ(void* fCallFtnEntry, unsigned attribs, OBJECTREF* pObjRefs, int numObjRefs)
1589 : HelperMethodFrame(fCallFtnEntry, attribs)
1590 {
1591 LIMITED_METHOD_CONTRACT;
1592 m_pObjRefs = pObjRefs;
1593 m_numObjRefs = numObjRefs;
1594#ifdef _DEBUG
1595 for (UINT i = 0; i < m_numObjRefs; i++) {
1596 Thread::ObjectRefProtected(&m_pObjRefs[i]);
1597 m_pObjRefs[i].Validate();
1598 }
1599#endif
1600 }
1601#endif
1602
1603 virtual void GcScanRoots(promote_func *fn, ScanContext* sc)
1604 {
1605 WRAPPER_NO_CONTRACT;
1606 for (UINT i = 0; i < m_numObjRefs; i++) {
1607 DoPromote(fn, sc, &m_pObjRefs[i], FALSE);
1608 }
1609 HelperMethodFrame::GcScanRoots(fn, sc);
1610 }
1611
1612#ifdef _DEBUG
1613#ifndef DACCESS_COMPILE
1614 void Pop()
1615 {
1616 WRAPPER_NO_CONTRACT;
1617 HelperMethodFrame::Pop();
1618 for (UINT i = 0; i < m_numObjRefs; i++) {
1619 Thread::ObjectRefNew(&m_pObjRefs[i]);
1620 }
1621 }
1622#endif // DACCESS_COMPILE
1623
1624 BOOL Protects(OBJECTREF *ppORef)
1625 {
1626 LIMITED_METHOD_CONTRACT;
1627 for (UINT i = 0; i < m_numObjRefs; i++) {
1628 if (ppORef == &m_pObjRefs[i])
1629 return TRUE;
1630 }
1631 return FALSE;
1632 }
1633#endif
1634
1635private:
1636 PTR_OBJECTREF m_pObjRefs;
1637 UINT m_numObjRefs;
1638
1639 // Keep as last entry in class
1640 DEFINE_VTABLE_GETTER_AND_CTOR_AND_DTOR(HelperMethodFrame_PROTECTOBJ)
1641};
1642
1643class FramedMethodFrame : public TransitionFrame
1644{
1645 VPTR_ABSTRACT_VTABLE_CLASS(FramedMethodFrame, TransitionFrame)
1646
1647 TADDR m_pTransitionBlock;
1648
1649protected:
1650 PTR_MethodDesc m_pMD;
1651
1652public:
1653#ifndef DACCESS_COMPILE
1654 FramedMethodFrame(TransitionBlock * pTransitionBlock, MethodDesc * pMD)
1655 : m_pTransitionBlock(dac_cast<TADDR>(pTransitionBlock)), m_pMD(pMD)
1656 {
1657 LIMITED_METHOD_CONTRACT;
1658 }
1659#endif // DACCESS_COMPILE
1660
1661 virtual TADDR GetTransitionBlock()
1662 {
1663 LIMITED_METHOD_DAC_CONTRACT;
1664 return m_pTransitionBlock;
1665 }
1666
1667 virtual MethodDesc *GetFunction()
1668 {
1669 LIMITED_METHOD_DAC_CONTRACT;
1670 return m_pMD;
1671 }
1672
1673#ifndef DACCESS_COMPILE
1674 void SetFunction(MethodDesc *pMD)
1675 {
1676 CONTRACTL
1677 {
1678 NOTHROW;
1679 GC_NOTRIGGER;
1680 MODE_COOPERATIVE; // Frame MethodDesc should be always updated in cooperative mode to avoid racing with GC stackwalk
1681 SO_TOLERANT;
1682 }
1683 CONTRACTL_END;
1684
1685 m_pMD = pMD;
1686 }
1687#endif
1688
1689 virtual ETransitionType GetTransitionType()
1690 {
1691 LIMITED_METHOD_DAC_CONTRACT;
1692 return TT_M2U; // we can safely cast to a FramedMethodFrame
1693 }
1694
1695 int GetFrameType()
1696 {
1697 LIMITED_METHOD_DAC_CONTRACT;
1698 return TYPE_CALL;
1699 }
1700
1701#ifdef COM_STUBS_SEPARATE_FP_LOCATIONS
1702 static int GetFPArgOffset(int iArg)
1703 {
1704#ifdef _TARGET_AMD64_
1705 // Floating point spill area is between return value and transition block for frames that need it
1706 // (code:TPMethodFrame and code:ComPlusMethodFrame)
1707 return -(4 * 0x10 /* floating point args */ + 0x8 /* alignment pad */ + TransitionBlock::GetNegSpaceSize()) + (iArg * 0x10);
1708#endif
1709 }
1710#endif
1711
1712 //
1713 // GetReturnObjectPtr and GetReturnValuePtr are only valid on frames
1714 // that allocate
1715 //
1716 PTR_PTR_Object GetReturnObjectPtr()
1717 {
1718 LIMITED_METHOD_DAC_CONTRACT;
1719 return PTR_PTR_Object(GetReturnValuePtr());
1720 }
1721
1722 // Get return value address
1723 PTR_VOID GetReturnValuePtr()
1724 {
1725 LIMITED_METHOD_DAC_CONTRACT;
1726#ifdef COM_STUBS_SEPARATE_FP_LOCATIONS
1727 TADDR p = GetTransitionBlock() + GetFPArgOffset(0);
1728#else
1729 TADDR p = GetTransitionBlock() - TransitionBlock::GetNegSpaceSize();
1730#endif
1731 // Return value is right before the transition block (or floating point spill area on AMD64) for frames that need it
1732 // (code:TPMethodFrame and code:ComPlusMethodFrame)
1733#ifdef ENREGISTERED_RETURNTYPE_MAXSIZE
1734 p -= ENREGISTERED_RETURNTYPE_MAXSIZE;
1735#else
1736 p -= sizeof(ARG_SLOT);
1737#endif
1738 return dac_cast<PTR_VOID>(p);
1739 }
1740
1741protected:
1742 FramedMethodFrame()
1743 {
1744 LIMITED_METHOD_CONTRACT;
1745 }
1746};
1747
1748//+----------------------------------------------------------------------------
1749//
1750// Class: TPMethodFrame private
1751//
1752// Synopsis: This frame is pushed onto the stack for calls on transparent
1753// proxy
1754//
1755//
1756//+----------------------------------------------------------------------------
1757
1758//------------------------------------------------------------------------
1759// This represents a call Delegate.Invoke for secure delegate
1760// It's only used to gc-protect the arguments during the call.
1761// Actually the only reason to have this frame is so a proper
1762// Assembly can be reported
1763//------------------------------------------------------------------------
1764
1765class SecureDelegateFrame : public TransitionFrame
1766{
1767 VPTR_VTABLE_CLASS(SecureDelegateFrame, TransitionFrame)
1768
1769 PTR_MethodDesc m_pMD;
1770 TransitionBlock m_TransitionBlock;
1771
1772public:
1773 virtual MethodDesc* GetFunction()
1774 {
1775 LIMITED_METHOD_CONTRACT;
1776 return m_pMD;
1777 }
1778
1779 virtual TADDR GetTransitionBlock()
1780 {
1781 LIMITED_METHOD_DAC_CONTRACT;
1782 return PTR_HOST_MEMBER_TADDR(SecureDelegateFrame, this,
1783 m_TransitionBlock);
1784 }
1785
1786 static BYTE GetOffsetOfDatum()
1787 {
1788 LIMITED_METHOD_DAC_CONTRACT;
1789 return offsetof(SecureDelegateFrame, m_pMD);
1790 }
1791
1792 static int GetOffsetOfTransitionBlock()
1793 {
1794 LIMITED_METHOD_DAC_CONTRACT;
1795 return offsetof(SecureDelegateFrame, m_TransitionBlock);
1796 }
1797
1798 virtual void GcScanRoots(promote_func *fn, ScanContext* sc)
1799 {
1800 WRAPPER_NO_CONTRACT;
1801 TransitionFrame::GcScanRoots(fn, sc);
1802 PromoteCallerStack(fn, sc);
1803 }
1804
1805 virtual Assembly *GetAssembly();
1806
1807 int GetFrameType()
1808 {
1809 LIMITED_METHOD_DAC_CONTRACT;
1810 return TYPE_MULTICAST;
1811 }
1812
1813 // For the debugger:
1814 // Our base class, FramedMethodFrame, is a M2U transition;
1815 // but Delegate.Invoke isn't. So override and fix it here.
1816 // If we didn't do this, we'd see a Managed/Unmanaged transition in debugger's stack trace.
1817 virtual ETransitionType GetTransitionType()
1818 {
1819 LIMITED_METHOD_DAC_CONTRACT;
1820 return TT_NONE;
1821 }
1822
1823 virtual BOOL TraceFrame(Thread *thread, BOOL fromPatch,
1824 TraceDestination *trace, REGDISPLAY *regs);
1825
1826 // Keep as last entry in class
1827 DEFINE_VTABLE_GETTER_AND_CTOR_AND_DTOR(SecureDelegateFrame)
1828};
1829
1830
1831//------------------------------------------------------------------------
1832// This represents a call Multicast.Invoke. It's only used to gc-protect
1833// the arguments during the iteration.
1834//------------------------------------------------------------------------
1835
1836class MulticastFrame : public SecureDelegateFrame
1837{
1838 VPTR_VTABLE_CLASS(MulticastFrame, SecureDelegateFrame)
1839
1840 public:
1841
1842 virtual Assembly *GetAssembly()
1843 {
1844 WRAPPER_NO_CONTRACT;
1845 return Frame::GetAssembly();
1846 }
1847
1848 int GetFrameType()
1849 {
1850 LIMITED_METHOD_DAC_CONTRACT;
1851 return TYPE_MULTICAST;
1852 }
1853
1854 virtual BOOL TraceFrame(Thread *thread, BOOL fromPatch,
1855 TraceDestination *trace, REGDISPLAY *regs);
1856
1857 // Keep as last entry in class
1858 DEFINE_VTABLE_GETTER_AND_CTOR_AND_DTOR(MulticastFrame)
1859};
1860
1861
1862//-----------------------------------------------------------------------
1863// Transition frame from unmanaged to managed
1864//-----------------------------------------------------------------------
1865
1866class UnmanagedToManagedFrame : public Frame
1867{
1868 friend class CheckAsmOffsets;
1869
1870 VPTR_ABSTRACT_VTABLE_CLASS_AND_CTOR(UnmanagedToManagedFrame, Frame)
1871
1872public:
1873
1874 // DACCESS: GetReturnAddressPtr should return the
1875 // target address of the return address in the frame.
1876 virtual TADDR GetReturnAddressPtr()
1877 {
1878 LIMITED_METHOD_DAC_CONTRACT;
1879 return PTR_HOST_MEMBER_TADDR(UnmanagedToManagedFrame, this,
1880 m_ReturnAddress);
1881 }
1882
1883 virtual PCODE GetReturnAddress();
1884
1885 // Retrieves pointer to the lowest-addressed argument on
1886 // the stack. Depending on the calling convention, this
1887 // may or may not be the first argument.
1888 TADDR GetPointerToArguments()
1889 {
1890 LIMITED_METHOD_DAC_CONTRACT;
1891 return dac_cast<TADDR>(this) + GetOffsetOfArgs();
1892 }
1893
1894 // Exposes an offset for stub generation.
1895 static BYTE GetOffsetOfArgs()
1896 {
1897 LIMITED_METHOD_DAC_CONTRACT;
1898#if defined(_TARGET_ARM_) || defined(_TARGET_ARM64_)
1899 size_t ofs = offsetof(UnmanagedToManagedFrame, m_argumentRegisters);
1900#else
1901 size_t ofs = sizeof(UnmanagedToManagedFrame);
1902#endif
1903 _ASSERTE(FitsInI1(ofs));
1904 return (BYTE)ofs;
1905 }
1906
1907 // depends on the sub frames to return approp. type here
1908 TADDR GetDatum()
1909 {
1910 LIMITED_METHOD_DAC_CONTRACT;
1911 return m_pvDatum;
1912 }
1913
1914 static int GetOffsetOfDatum()
1915 {
1916 LIMITED_METHOD_CONTRACT;
1917 return offsetof(UnmanagedToManagedFrame, m_pvDatum);
1918 }
1919
1920#ifdef _TARGET_X86_
1921 static int GetOffsetOfCalleeSavedRegisters()
1922 {
1923 LIMITED_METHOD_CONTRACT;
1924 return offsetof(UnmanagedToManagedFrame, m_calleeSavedRegisters);
1925 }
1926#endif
1927
1928 int GetFrameType()
1929 {
1930 LIMITED_METHOD_DAC_CONTRACT;
1931 return TYPE_ENTRY;
1932 }
1933
1934 //------------------------------------------------------------------------
1935 // For the debugger.
1936 //------------------------------------------------------------------------
1937 virtual ETransitionType GetTransitionType()
1938 {
1939 LIMITED_METHOD_DAC_CONTRACT;
1940 return TT_U2M;
1941 }
1942
1943 //------------------------------------------------------------------------
1944 // Performs cleanup on an exception unwind
1945 //------------------------------------------------------------------------
1946#ifndef DACCESS_COMPILE
1947 virtual void ExceptionUnwind();
1948#endif
1949
1950protected:
1951 TADDR m_pvDatum; // type depends on the sub class
1952
1953#if defined(_TARGET_X86_)
1954 CalleeSavedRegisters m_calleeSavedRegisters;
1955 TADDR m_ReturnAddress;
1956#elif defined(_TARGET_ARM_)
1957 TADDR m_R11; // R11 chain
1958 TADDR m_ReturnAddress;
1959 ArgumentRegisters m_argumentRegisters;
1960#elif defined (_TARGET_ARM64_)
1961 TADDR m_fp;
1962 TADDR m_ReturnAddress;
1963 TADDR m_x8; // ret buff arg
1964 ArgumentRegisters m_argumentRegisters;
1965#else
1966 TADDR m_ReturnAddress; // return address into unmanaged code
1967#endif
1968};
1969
1970#ifdef FEATURE_COMINTEROP
1971
1972//------------------------------------------------------------------------
1973// This frame represents a transition from COM to COM+
1974//------------------------------------------------------------------------
1975
1976class ComMethodFrame : public UnmanagedToManagedFrame
1977{
1978 VPTR_VTABLE_CLASS(ComMethodFrame, UnmanagedToManagedFrame)
1979 VPTR_UNIQUE(VPTR_UNIQUE_ComMethodFrame)
1980
1981public:
1982
1983#ifdef _TARGET_X86_
1984 // Return the # of stack bytes pushed by the unmanaged caller.
1985 UINT GetNumCallerStackBytes();
1986#endif
1987
1988 PTR_ComCallMethodDesc GetComCallMethodDesc()
1989 {
1990 LIMITED_METHOD_CONTRACT;
1991 return dac_cast<PTR_ComCallMethodDesc>(m_pvDatum);
1992 }
1993
1994#ifndef DACCESS_COMPILE
1995 static void DoSecondPassHandlerCleanup(Frame * pCurFrame);
1996#endif // !DACCESS_COMPILE
1997
1998protected:
1999 // Keep as last entry in class
2000 DEFINE_VTABLE_GETTER_AND_CTOR_AND_DTOR(ComMethodFrame)
2001};
2002
2003typedef DPTR(class ComMethodFrame) PTR_ComMethodFrame;
2004
2005//------------------------------------------------------------------------
2006// This represents a generic call from CLR to COM
2007//------------------------------------------------------------------------
2008
2009class ComPlusMethodFrame : public FramedMethodFrame
2010{
2011 VPTR_VTABLE_CLASS(ComPlusMethodFrame, FramedMethodFrame)
2012
2013public:
2014 ComPlusMethodFrame(TransitionBlock * pTransitionBlock, MethodDesc * pMethodDesc);
2015
2016 virtual void GcScanRoots(promote_func *fn, ScanContext* sc);
2017
2018 virtual BOOL IsTransitionToNativeFrame()
2019 {
2020 LIMITED_METHOD_CONTRACT;
2021 return TRUE;
2022 }
2023
2024 int GetFrameType()
2025 {
2026 LIMITED_METHOD_DAC_CONTRACT;
2027 return TYPE_EXIT;
2028 }
2029
2030 void GetUnmanagedCallSite(TADDR* ip,
2031 TADDR* returnIP,
2032 TADDR* returnSP);
2033
2034 BOOL TraceFrame(Thread *thread, BOOL fromPatch,
2035 TraceDestination *trace, REGDISPLAY *regs);
2036
2037 // Keep as last entry in class
2038 DEFINE_VTABLE_GETTER_AND_CTOR_AND_DTOR(ComPlusMethodFrame)
2039};
2040
2041#endif // FEATURE_COMINTEROP
2042
2043//------------------------------------------------------------------------
2044// This represents a call from a helper to GetILStubForCalli
2045//------------------------------------------------------------------------
2046
2047class PInvokeCalliFrame : public FramedMethodFrame
2048{
2049 VPTR_VTABLE_CLASS(PInvokeCalliFrame, FramedMethodFrame)
2050
2051 PTR_VASigCookie m_pVASigCookie;
2052 PCODE m_pUnmanagedTarget;
2053
2054public:
2055 PInvokeCalliFrame(TransitionBlock * pTransitionBlock, VASigCookie * pVASigCookie, PCODE pUnmanagedTarget);
2056
2057 virtual void GcScanRoots(promote_func *fn, ScanContext* sc)
2058 {
2059 WRAPPER_NO_CONTRACT;
2060 FramedMethodFrame::GcScanRoots(fn, sc);
2061 PromoteCallerStack(fn, sc);
2062 }
2063
2064 void PromoteCallerStack(promote_func* fn, ScanContext* sc);
2065
2066 // not a method
2067 virtual MethodDesc *GetFunction()
2068 {
2069 LIMITED_METHOD_DAC_CONTRACT;
2070 return NULL;
2071 }
2072
2073 int GetFrameType()
2074 {
2075 LIMITED_METHOD_DAC_CONTRACT;
2076 return TYPE_INTERCEPTION;
2077 }
2078
2079 PCODE GetPInvokeCalliTarget()
2080 {
2081 LIMITED_METHOD_CONTRACT;
2082 return m_pUnmanagedTarget;
2083 }
2084
2085 PTR_VASigCookie GetVASigCookie()
2086 {
2087 LIMITED_METHOD_CONTRACT;
2088 return m_pVASigCookie;
2089 }
2090
2091#ifdef _TARGET_X86_
2092 virtual void UpdateRegDisplay(const PREGDISPLAY);
2093#endif // _TARGET_X86_
2094
2095 BOOL TraceFrame(Thread *thread, BOOL fromPatch,
2096 TraceDestination *trace, REGDISPLAY *regs)
2097 {
2098 WRAPPER_NO_CONTRACT;
2099
2100 trace->InitForUnmanaged(GetPInvokeCalliTarget());
2101 return TRUE;
2102 }
2103
2104 // Keep as last entry in class
2105 DEFINE_VTABLE_GETTER_AND_CTOR_AND_DTOR(PInvokeCalliFrame)
2106};
2107
2108// Some context-related forwards.
2109#ifdef FEATURE_HIJACK
2110//------------------------------------------------------------------------
2111// This frame represents a hijacked return. If we crawl back through it,
2112// it gets us back to where the return should have gone (and eventually will
2113// go).
2114//------------------------------------------------------------------------
2115class HijackFrame : public Frame
2116{
2117 VPTR_VTABLE_CLASS(HijackFrame, Frame)
2118 VPTR_UNIQUE(VPTR_UNIQUE_HijackFrame);
2119
2120public:
2121 // DACCESS: GetReturnAddressPtr should return the
2122 // target address of the return address in the frame.
2123 virtual TADDR GetReturnAddressPtr()
2124 {
2125 LIMITED_METHOD_DAC_CONTRACT;
2126 return PTR_HOST_MEMBER_TADDR(HijackFrame, this,
2127 m_ReturnAddress);
2128 }
2129
2130 virtual BOOL NeedsUpdateRegDisplay()
2131 {
2132 LIMITED_METHOD_CONTRACT;
2133 return TRUE;
2134 }
2135
2136 virtual void UpdateRegDisplay(const PREGDISPLAY);
2137 virtual void GcScanRoots(promote_func *fn, ScanContext* sc);
2138
2139 // HijackFrames are created by trip functions. See OnHijackTripThread()
2140 // They are real C++ objects on the stack.
2141 // So, it's a public function -- but that doesn't mean you should make some.
2142 HijackFrame(LPVOID returnAddress, Thread *thread, HijackArgs *args);
2143
2144protected:
2145
2146 TADDR m_ReturnAddress;
2147 PTR_Thread m_Thread;
2148 DPTR(HijackArgs) m_Args;
2149
2150 // Keep as last entry in class
2151 DEFINE_VTABLE_GETTER_AND_CTOR_AND_DTOR(HijackFrame)
2152};
2153
2154#endif // FEATURE_HIJACK
2155
2156//------------------------------------------------------------------------
2157// This represents a call to a method prestub. Because the prestub
2158// can do gc and throw exceptions while building the replacement
2159// stub, we need this frame to keep things straight.
2160//------------------------------------------------------------------------
2161
2162class PrestubMethodFrame : public FramedMethodFrame
2163{
2164 VPTR_VTABLE_CLASS(PrestubMethodFrame, FramedMethodFrame)
2165
2166public:
2167 PrestubMethodFrame(TransitionBlock * pTransitionBlock, MethodDesc * pMD);
2168
2169 virtual void GcScanRoots(promote_func *fn, ScanContext* sc)
2170 {
2171 WRAPPER_NO_CONTRACT;
2172 FramedMethodFrame::GcScanRoots(fn, sc);
2173 PromoteCallerStack(fn, sc);
2174 }
2175
2176 BOOL TraceFrame(Thread *thread, BOOL fromPatch,
2177 TraceDestination *trace, REGDISPLAY *regs);
2178
2179 int GetFrameType()
2180 {
2181 LIMITED_METHOD_DAC_CONTRACT;
2182 return TYPE_INTERCEPTION;
2183 }
2184
2185 // Our base class is a a M2U TransitionType; but we're not. So override and set us back to None.
2186 ETransitionType GetTransitionType()
2187 {
2188 LIMITED_METHOD_DAC_CONTRACT;
2189 return TT_NONE;
2190 }
2191
2192 Interception GetInterception();
2193
2194 // Keep as last entry in class
2195 DEFINE_VTABLE_GETTER_AND_CTOR_AND_DTOR(PrestubMethodFrame)
2196};
2197
2198//------------------------------------------------------------------------
2199// This represents a call into the virtual call stub manager
2200// Because the stub manager can do gc and throw exceptions while
2201// building the resolve and dispatch stubs and needs to communicate
2202// if we need to setup for a methodDesc call or do a direct call
2203// we need this frame to keep things straight.
2204//------------------------------------------------------------------------
2205
2206class StubDispatchFrame : public FramedMethodFrame
2207{
2208 VPTR_VTABLE_CLASS(StubDispatchFrame, FramedMethodFrame)
2209
2210 // Representative MethodTable * and slot. They are used to
2211 // compute the MethodDesc* lazily
2212 PTR_MethodTable m_pRepresentativeMT;
2213 UINT32 m_representativeSlot;
2214
2215 // Indirection cell and containing module. Used to compute pGCRefMap lazily.
2216 PTR_Module m_pZapModule;
2217 TADDR m_pIndirection;
2218
2219 // Cached pointer to native ref data.
2220 PTR_BYTE m_pGCRefMap;
2221
2222public:
2223 StubDispatchFrame(TransitionBlock * pTransitionBlock);
2224
2225 MethodDesc* GetFunction();
2226
2227 // Returns this frame GC ref map if it has one
2228 PTR_BYTE GetGCRefMap();
2229
2230#ifdef _TARGET_X86_
2231 virtual void UpdateRegDisplay(const PREGDISPLAY pRD);
2232 virtual PCODE GetReturnAddress();
2233#endif // _TARGET_X86_
2234
2235 PCODE GetUnadjustedReturnAddress()
2236 {
2237 LIMITED_METHOD_DAC_CONTRACT;
2238 return FramedMethodFrame::GetReturnAddress();
2239 }
2240
2241 virtual void GcScanRoots(promote_func *fn, ScanContext* sc);
2242
2243#ifndef DACCESS_COMPILE
2244 void SetRepresentativeSlot(MethodTable * pMT, UINT32 representativeSlot)
2245 {
2246 LIMITED_METHOD_CONTRACT;
2247
2248 m_pRepresentativeMT = pMT;
2249 m_representativeSlot = representativeSlot;
2250 }
2251
2252 void SetCallSite(Module * pZapModule, TADDR pIndirection)
2253 {
2254 LIMITED_METHOD_CONTRACT;
2255
2256 m_pZapModule = pZapModule;
2257 m_pIndirection = pIndirection;
2258 }
2259
2260 void SetForNullReferenceException()
2261 {
2262 LIMITED_METHOD_CONTRACT;
2263
2264 // Nothing to do. Everything is initialized in Init.
2265 }
2266#endif
2267
2268 BOOL TraceFrame(Thread *thread, BOOL fromPatch,
2269 TraceDestination *trace, REGDISPLAY *regs);
2270
2271 int GetFrameType()
2272 {
2273 LIMITED_METHOD_CONTRACT;
2274 return TYPE_CALL;
2275 }
2276
2277 Interception GetInterception();
2278
2279 virtual BOOL SuppressParamTypeArg()
2280 {
2281 //
2282 // Shared default interface methods (i.e. virtual interface methods with an implementation) require
2283 // an instantiation argument. But if we're in the stub dispatch frame, we haven't actually resolved
2284 // the method yet (we could end up in class's override of this method, for example).
2285 //
2286 // So we need to pretent that unresolved default interface methods are like any other interface
2287 // methods and don't have an instantiation argument.
2288 //
2289 // See code:CEEInfo::getMethodSigInternal
2290 //
2291 assert(GetFunction()->GetMethodTable()->IsInterface());
2292 return TRUE;
2293 }
2294
2295private:
2296 friend class VirtualCallStubManager;
2297
2298 // Keep as last entry in class
2299 DEFINE_VTABLE_GETTER_AND_CTOR_AND_DTOR(StubDispatchFrame)
2300};
2301
2302typedef VPTR(class StubDispatchFrame) PTR_StubDispatchFrame;
2303
2304
2305//------------------------------------------------------------------------
2306// This represents a call from an ExternalMethodThunk or a VirtualImportThunk
2307// Because the resolving of the target address can do gc and/or
2308// throw exceptions we need this frame to report the gc references.
2309//------------------------------------------------------------------------
2310
2311class ExternalMethodFrame : public FramedMethodFrame
2312{
2313 VPTR_VTABLE_CLASS(ExternalMethodFrame, FramedMethodFrame)
2314
2315 // Indirection and containing module. Used to compute pGCRefMap lazily.
2316 PTR_Module m_pZapModule;
2317 TADDR m_pIndirection;
2318
2319 // Cached pointer to native ref data.
2320 PTR_BYTE m_pGCRefMap;
2321
2322public:
2323 ExternalMethodFrame(TransitionBlock * pTransitionBlock);
2324
2325 virtual void GcScanRoots(promote_func *fn, ScanContext* sc);
2326
2327 // Returns this frame GC ref map if it has one
2328 PTR_BYTE GetGCRefMap();
2329
2330#ifndef DACCESS_COMPILE
2331 void SetCallSite(Module * pZapModule, TADDR pIndirection)
2332 {
2333 LIMITED_METHOD_CONTRACT;
2334
2335 m_pZapModule = pZapModule;
2336 m_pIndirection = pIndirection;
2337 }
2338#endif
2339
2340 int GetFrameType()
2341 {
2342 LIMITED_METHOD_CONTRACT;
2343 return TYPE_CALL;
2344 }
2345
2346 Interception GetInterception();
2347
2348#ifdef _TARGET_X86_
2349 virtual void UpdateRegDisplay(const PREGDISPLAY pRD);
2350#endif
2351
2352 // Keep as last entry in class
2353 DEFINE_VTABLE_GETTER_AND_CTOR_AND_DTOR(ExternalMethodFrame)
2354};
2355
2356typedef VPTR(class ExternalMethodFrame) PTR_ExternalMethodFrame;
2357
2358#ifdef FEATURE_READYTORUN
2359class DynamicHelperFrame : public FramedMethodFrame
2360{
2361 VPTR_VTABLE_CLASS(DynamicHelperFrame, FramedMethodFrame)
2362
2363 int m_dynamicHelperFrameFlags;
2364
2365public:
2366 DynamicHelperFrame(TransitionBlock * pTransitionBlock, int dynamicHelperFrameFlags);
2367
2368 virtual void GcScanRoots(promote_func *fn, ScanContext* sc);
2369
2370#ifdef _TARGET_X86_
2371 virtual void UpdateRegDisplay(const PREGDISPLAY pRD);
2372#endif
2373
2374 virtual ETransitionType GetTransitionType()
2375 {
2376 LIMITED_METHOD_DAC_CONTRACT;
2377 return TT_InternalCall;
2378 }
2379
2380 // Keep as last entry in class
2381 DEFINE_VTABLE_GETTER_AND_CTOR_AND_DTOR(DynamicHelperFrame)
2382};
2383
2384typedef VPTR(class DynamicHelperFrame) PTR_DynamicHelperFrame;
2385#endif // FEATURE_READYTORUN
2386
2387//------------------------------------------------------------------------
2388// This frame is used for instantiating stubs when the argument transform
2389// is too complex to generate a tail-calling stub.
2390//------------------------------------------------------------------------
2391#if !defined(_TARGET_X86_)
2392class StubHelperFrame : public TransitionFrame
2393{
2394 friend class CheckAsmOffsets;
2395 friend class StubLinkerCPU;
2396
2397 VPTR_VTABLE_CLASS(StubHelperFrame, TransitionFrame)
2398 VPTR_UNIQUE(VPTR_UNIQUE_StubHelperFrame)
2399
2400 TransitionBlock m_TransitionBlock;
2401
2402 virtual TADDR GetTransitionBlock()
2403 {
2404 LIMITED_METHOD_DAC_CONTRACT;
2405 return PTR_HOST_MEMBER_TADDR(StubHelperFrame, this,
2406 m_TransitionBlock);
2407 }
2408
2409 static int GetOffsetOfTransitionBlock()
2410 {
2411 LIMITED_METHOD_DAC_CONTRACT;
2412 return offsetof(StubHelperFrame, m_TransitionBlock);
2413 }
2414
2415private:
2416 // Keep as last entry in class
2417 DEFINE_VTABLE_GETTER_AND_CTOR_AND_DTOR(StubHelperFrame)
2418};
2419#endif // _TARGET_X86_
2420
2421#ifdef FEATURE_COMINTEROP
2422
2423//------------------------------------------------------------------------
2424// This represents a com to com+ call method prestub.
2425// we need to catch exceptions etc. so this frame is not the same
2426// as the prestub method frame
2427// Note that in rare IJW cases, the immediate caller could be a managed method
2428// which pinvoke-inlined a call to a COM interface, which happenned to be
2429// implemented by a managed function via COM-interop.
2430//------------------------------------------------------------------------
2431class ComPrestubMethodFrame : public ComMethodFrame
2432{
2433 friend class CheckAsmOffsets;
2434
2435 VPTR_VTABLE_CLASS(ComPrestubMethodFrame, ComMethodFrame)
2436
2437public:
2438 // Set the vptr and GSCookie
2439 VOID Init();
2440
2441 int GetFrameType()
2442 {
2443 LIMITED_METHOD_DAC_CONTRACT;
2444 return TYPE_INTERCEPTION;
2445 }
2446
2447 // ComPrestubMethodFrame should return the same interception type as
2448 // code:PrestubMethodFrame.GetInterception.
2449 virtual Interception GetInterception()
2450 {
2451 LIMITED_METHOD_DAC_CONTRACT;
2452 return INTERCEPTION_PRESTUB;
2453 }
2454
2455 // Our base class is a a M2U TransitionType; but we're not. So override and set us back to None.
2456 virtual ETransitionType GetTransitionType()
2457 {
2458 LIMITED_METHOD_DAC_CONTRACT;
2459 return TT_NONE;
2460 }
2461
2462 virtual void ExceptionUnwind()
2463 {
2464 }
2465
2466private:
2467 // Keep as last entry in class
2468 DEFINE_VTABLE_GETTER_AND_CTOR_AND_DTOR(ComPrestubMethodFrame)
2469};
2470
2471#endif // FEATURE_COMINTEROP
2472
2473
2474//------------------------------------------------------------------------
2475// This frame protects object references for the EE's convenience.
2476// This frame type actually is created from C++.
2477//------------------------------------------------------------------------
2478class GCFrame : public Frame
2479{
2480 VPTR_VTABLE_CLASS(GCFrame, Frame)
2481
2482public:
2483
2484
2485 //--------------------------------------------------------------------
2486 // This constructor pushes a new GCFrame on the frame chain.
2487 //--------------------------------------------------------------------
2488#ifndef DACCESS_COMPILE
2489 GCFrame() {
2490 LIMITED_METHOD_CONTRACT;
2491 };
2492
2493 GCFrame(OBJECTREF *pObjRefs, UINT numObjRefs, BOOL maybeInterior);
2494 GCFrame(Thread *pThread, OBJECTREF *pObjRefs, UINT numObjRefs, BOOL maybeInterior);
2495#endif
2496 void Init(Thread *pThread, OBJECTREF *pObjRefs, UINT numObjRefs, BOOL maybeInterior);
2497
2498
2499 //--------------------------------------------------------------------
2500 // Pops the GCFrame and cancels the GC protection. Also
2501 // trashes the contents of pObjRef's in _DEBUG.
2502 //--------------------------------------------------------------------
2503 VOID Pop();
2504
2505 virtual void GcScanRoots(promote_func *fn, ScanContext* sc);
2506
2507#ifdef _DEBUG
2508 virtual BOOL Protects(OBJECTREF *ppORef)
2509 {
2510 LIMITED_METHOD_CONTRACT;
2511 for (UINT i = 0; i < m_numObjRefs; i++) {
2512 if (ppORef == m_pObjRefs + i) {
2513 return TRUE;
2514 }
2515 }
2516 return FALSE;
2517 }
2518#endif
2519
2520#ifndef DACCESS_COMPILE
2521 void *operator new (size_t sz, void* p)
2522 {
2523 LIMITED_METHOD_CONTRACT;
2524 return p ;
2525 }
2526#endif
2527
2528#if defined(_DEBUG_IMPL)
2529 const char* GetFrameTypeName() { LIMITED_METHOD_CONTRACT; return "GCFrame"; }
2530#endif
2531
2532private:
2533 PTR_OBJECTREF m_pObjRefs;
2534 UINT m_numObjRefs;
2535 PTR_Thread m_pCurThread;
2536 BOOL m_MaybeInterior;
2537
2538 // Keep as last entry in class
2539 DEFINE_VTABLE_GETTER_AND_DTOR(GCFrame)
2540};
2541
2542#ifdef FEATURE_INTERPRETER
2543class InterpreterFrame: public Frame
2544{
2545 VPTR_VTABLE_CLASS(InterpreterFrame, Frame)
2546
2547 class Interpreter* m_interp;
2548
2549public:
2550
2551#ifndef DACCESS_COMPILE
2552 InterpreterFrame(class Interpreter* interp);
2553
2554 class Interpreter* GetInterpreter() { return m_interp; }
2555
2556 // Override.
2557 virtual void GcScanRoots(promote_func *fn, ScanContext* sc);
2558
2559 MethodDesc* GetFunction();
2560#endif
2561
2562 DEFINE_VTABLE_GETTER_AND_DTOR(InterpreterFrame)
2563
2564};
2565
2566typedef VPTR(class InterpreterFrame) PTR_InterpreterFrame;
2567#endif // FEATURE_INTERPRETER
2568
2569
2570//-----------------------------------------------------------------------------
2571
2572struct ByRefInfo;
2573typedef DPTR(ByRefInfo) PTR_ByRefInfo;
2574
2575struct ByRefInfo
2576{
2577 PTR_ByRefInfo pNext;
2578 INT32 argIndex;
2579 CorElementType typ;
2580 TypeHandle typeHandle;
2581 char data[1];
2582};
2583
2584//-----------------------------------------------------------------------------
2585// ProtectByRefsFrame
2586//-----------------------------------------------------------------------------
2587
2588class ProtectByRefsFrame : public Frame
2589{
2590 VPTR_VTABLE_CLASS(ProtectByRefsFrame, Frame)
2591
2592public:
2593#ifndef DACCESS_COMPILE
2594 ProtectByRefsFrame(Thread *pThread, ByRefInfo *brInfo)
2595 : m_brInfo(brInfo)
2596 {
2597 WRAPPER_NO_CONTRACT;
2598 Frame::Push(pThread);
2599 }
2600#endif
2601
2602 virtual void GcScanRoots(promote_func *fn, ScanContext *sc);
2603
2604private:
2605 PTR_ByRefInfo m_brInfo;
2606
2607 // Keep as last entry in class
2608 DEFINE_VTABLE_GETTER_AND_CTOR_AND_DTOR(ProtectByRefsFrame)
2609};
2610
2611
2612//-----------------------------------------------------------------------------
2613
2614struct ValueClassInfo;
2615typedef DPTR(struct ValueClassInfo) PTR_ValueClassInfo;
2616
2617struct ValueClassInfo
2618{
2619 PTR_ValueClassInfo pNext;
2620 PTR_MethodTable pMT;
2621 PTR_VOID pData;
2622
2623 ValueClassInfo(PTR_VOID aData, PTR_MethodTable aMT, PTR_ValueClassInfo aNext)
2624 : pNext(aNext), pMT(aMT), pData(aData)
2625 {
2626 }
2627};
2628
2629//-----------------------------------------------------------------------------
2630// ProtectValueClassFrame
2631//-----------------------------------------------------------------------------
2632
2633
2634class ProtectValueClassFrame : public Frame
2635{
2636 VPTR_VTABLE_CLASS(ProtectValueClassFrame, Frame)
2637
2638public:
2639#ifndef DACCESS_COMPILE
2640 ProtectValueClassFrame()
2641 : m_pVCInfo(NULL)
2642 {
2643 WRAPPER_NO_CONTRACT;
2644 Frame::Push();
2645 }
2646
2647 ProtectValueClassFrame(Thread *pThread, ValueClassInfo *vcInfo)
2648 : m_pVCInfo(vcInfo)
2649 {
2650 WRAPPER_NO_CONTRACT;
2651 Frame::Push(pThread);
2652 }
2653#endif
2654
2655 virtual void GcScanRoots(promote_func *fn, ScanContext *sc);
2656
2657 ValueClassInfo ** GetValueClassInfoList()
2658 {
2659 LIMITED_METHOD_CONTRACT;
2660 return &m_pVCInfo;
2661 }
2662
2663private:
2664
2665 ValueClassInfo *m_pVCInfo;
2666
2667 // Keep as last entry in class
2668 DEFINE_VTABLE_GETTER_AND_DTOR(ProtectValueClassFrame)
2669};
2670
2671
2672#ifdef _DEBUG
2673BOOL IsProtectedByGCFrame(OBJECTREF *ppObjectRef);
2674#endif
2675
2676
2677//------------------------------------------------------------------------
2678// DebuggerClassInitMarkFrame is a small frame whose only purpose in
2679// life is to mark for the debugger that "class initialization code" is
2680// being run. It does nothing useful except return good values from
2681// GetFrameType and GetInterception.
2682//------------------------------------------------------------------------
2683
2684class DebuggerClassInitMarkFrame : public Frame
2685{
2686 VPTR_VTABLE_CLASS(DebuggerClassInitMarkFrame, Frame)
2687
2688public:
2689
2690#ifndef DACCESS_COMPILE
2691 DebuggerClassInitMarkFrame()
2692 {
2693 WRAPPER_NO_CONTRACT;
2694 Push();
2695 };
2696#endif
2697
2698 virtual int GetFrameType()
2699 {
2700 LIMITED_METHOD_DAC_CONTRACT;
2701 return TYPE_INTERCEPTION;
2702 }
2703
2704 virtual Interception GetInterception()
2705 {
2706 LIMITED_METHOD_DAC_CONTRACT;
2707 return INTERCEPTION_CLASS_INIT;
2708 }
2709
2710 // Keep as last entry in class
2711 DEFINE_VTABLE_GETTER_AND_DTOR(DebuggerClassInitMarkFrame)
2712};
2713
2714
2715//------------------------------------------------------------------------
2716// DebuggerSecurityCodeMarkFrame is a small frame whose only purpose in
2717// life is to mark for the debugger that "security code" is
2718// being run. It does nothing useful except return good values from
2719// GetFrameType and GetInterception.
2720//------------------------------------------------------------------------
2721
2722class DebuggerSecurityCodeMarkFrame : public Frame
2723{
2724 VPTR_VTABLE_CLASS(DebuggerSecurityCodeMarkFrame, Frame)
2725
2726public:
2727#ifndef DACCESS_COMPILE
2728 DebuggerSecurityCodeMarkFrame()
2729 {
2730 WRAPPER_NO_CONTRACT;
2731 Push();
2732 }
2733#endif
2734
2735 virtual int GetFrameType()
2736 {
2737 LIMITED_METHOD_DAC_CONTRACT;
2738 return TYPE_INTERCEPTION;
2739 }
2740
2741 virtual Interception GetInterception()
2742 {
2743 LIMITED_METHOD_DAC_CONTRACT;
2744 return INTERCEPTION_SECURITY;
2745 }
2746
2747 // Keep as last entry in class
2748 DEFINE_VTABLE_GETTER_AND_DTOR(DebuggerSecurityCodeMarkFrame)
2749};
2750
2751//------------------------------------------------------------------------
2752// DebuggerExitFrame is a small frame whose only purpose in
2753// life is to mark for the debugger that there is an exit transiton on
2754// the stack. This is special cased for the "break" IL instruction since
2755// it is an fcall using a helper frame which returns TYPE_CALL instead of
2756// an ecall (as in System.Diagnostics.Debugger.Break()) which returns
2757// TYPE_EXIT. This just makes the two consistent for debugging services.
2758//------------------------------------------------------------------------
2759
2760class DebuggerExitFrame : public Frame
2761{
2762 VPTR_VTABLE_CLASS(DebuggerExitFrame, Frame)
2763
2764public:
2765#ifndef DACCESS_COMPILE
2766 DebuggerExitFrame()
2767 {
2768 WRAPPER_NO_CONTRACT;
2769 Push();
2770 }
2771#endif
2772
2773 virtual int GetFrameType()
2774 {
2775 LIMITED_METHOD_DAC_CONTRACT;
2776 return TYPE_EXIT;
2777 }
2778
2779 // Return information about an unmanaged call the frame
2780 // will make.
2781 // ip - the unmanaged routine which will be called
2782 // returnIP - the address in the stub which the unmanaged routine
2783 // will return to.
2784 // returnSP - the location returnIP is pushed onto the stack
2785 // during the call.
2786 //
2787 virtual void GetUnmanagedCallSite(TADDR* ip,
2788 TADDR* returnIP,
2789 TADDR* returnSP)
2790 {
2791 LIMITED_METHOD_CONTRACT;
2792 if (ip)
2793 *ip = NULL;
2794
2795 if (returnIP)
2796 *returnIP = NULL;
2797
2798 if (returnSP)
2799 *returnSP = NULL;
2800 }
2801
2802 // Keep as last entry in class
2803 DEFINE_VTABLE_GETTER_AND_DTOR(DebuggerExitFrame)
2804};
2805
2806//---------------------------------------------------------------------------------------
2807//
2808// DebuggerU2MCatchHandlerFrame is a small frame whose only purpose in life is to mark for the debugger
2809// that there is catch handler inside the runtime which may catch and swallow managed exceptions. The
2810// debugger needs this frame to send a CatchHandlerFound (CHF) notification. Without this frame, the
2811// debugger doesn't know where a managed exception is caught.
2812//
2813// Notes:
2814// Currently this frame is only used in code:DispatchInfo.InvokeMember, which is an U2M transition.
2815//
2816
2817class DebuggerU2MCatchHandlerFrame : public Frame
2818{
2819 VPTR_VTABLE_CLASS(DebuggerU2MCatchHandlerFrame, Frame)
2820
2821public:
2822#ifndef DACCESS_COMPILE
2823 DebuggerU2MCatchHandlerFrame()
2824 {
2825 WRAPPER_NO_CONTRACT;
2826 Frame::Push();
2827 }
2828
2829 DebuggerU2MCatchHandlerFrame(Thread * pThread)
2830 {
2831 WRAPPER_NO_CONTRACT;
2832 Frame::Push(pThread);
2833 }
2834#endif
2835
2836 ETransitionType GetTransitionType()
2837 {
2838 LIMITED_METHOD_DAC_CONTRACT;
2839 return TT_U2M;
2840 }
2841
2842 // Keep as last entry in class
2843 DEFINE_VTABLE_GETTER_AND_DTOR(DebuggerU2MCatchHandlerFrame)
2844};
2845
2846
2847class UMThunkMarshInfo;
2848typedef DPTR(class UMThunkMarshInfo) PTR_UMThunkMarshInfo;
2849
2850class UMEntryThunk;
2851typedef DPTR(class UMEntryThunk) PTR_UMEntryThunk;
2852
2853#if defined(_TARGET_X86_)
2854//------------------------------------------------------------------------
2855// This frame guards an unmanaged->managed transition thru a UMThk
2856//------------------------------------------------------------------------
2857
2858class UMThkCallFrame : public UnmanagedToManagedFrame
2859{
2860 VPTR_VTABLE_CLASS(UMThkCallFrame, UnmanagedToManagedFrame)
2861
2862public:
2863
2864#ifdef DACCESS_COMPILE
2865 virtual void EnumMemoryRegions(CLRDataEnumMemoryFlags flags);
2866#endif
2867
2868 PTR_UMEntryThunk GetUMEntryThunk();
2869
2870 static int GetOffsetOfUMEntryThunk()
2871 {
2872 WRAPPER_NO_CONTRACT;
2873 return GetOffsetOfDatum();
2874 }
2875
2876protected:
2877
2878 // Keep as last entry in class
2879 DEFINE_VTABLE_GETTER_AND_CTOR_AND_DTOR(UMThkCallFrame)
2880};
2881#endif // _TARGET_X86_ && !FEATURE_PAL
2882
2883#if defined(_TARGET_X86_) && defined(FEATURE_COMINTEROP)
2884//-------------------------------------------------------------------------
2885// Exception handler for COM to managed frame
2886// and the layout of the exception registration record structure in the stack
2887// the layout is similar to the NT's EXCEPTIONREGISTRATION record
2888// followed by the UnmanagedToManagedFrame specific info
2889
2890struct ComToManagedExRecord
2891{
2892 EXCEPTION_REGISTRATION_RECORD m_ExReg;
2893 ArgumentRegisters m_argRegs;
2894 GSCookie m_gsCookie;
2895 UMThkCallFrame m_frame;
2896
2897 UnmanagedToManagedFrame * GetCurrFrame()
2898 {
2899 LIMITED_METHOD_CONTRACT;
2900 return &m_frame;
2901 }
2902};
2903#endif // _TARGET_X86_ && FEATURE_COMINTEROP
2904
2905
2906//------------------------------------------------------------------------
2907// This frame is pushed by any JIT'ted method that contains one or more
2908// inlined N/Direct calls. Note that the JIT'ted method keeps it pushed
2909// the whole time to amortize the pushing cost across the entire method.
2910//------------------------------------------------------------------------
2911
2912typedef DPTR(class InlinedCallFrame) PTR_InlinedCallFrame;
2913
2914class InlinedCallFrame : public Frame
2915{
2916 VPTR_VTABLE_CLASS(InlinedCallFrame, Frame)
2917
2918public:
2919 virtual MethodDesc *GetFunction()
2920 {
2921 WRAPPER_NO_CONTRACT;
2922 if (FrameHasActiveCall(this) && HasFunction())
2923 return PTR_MethodDesc(m_Datum);
2924 else
2925 return NULL;
2926 }
2927
2928 BOOL HasFunction()
2929 {
2930 WRAPPER_NO_CONTRACT;
2931
2932#ifdef _WIN64
2933 // See code:GenericPInvokeCalliHelper
2934 return ((m_Datum != NULL) && !(dac_cast<TADDR>(m_Datum) & 0x1));
2935#else // _WIN64
2936 return ((dac_cast<TADDR>(m_Datum) & ~0xffff) != 0);
2937#endif // _WIN64
2938 }
2939
2940 // Retrieves the return address into the code that called out
2941 // to managed code
2942 virtual TADDR GetReturnAddressPtr()
2943 {
2944 WRAPPER_NO_CONTRACT;
2945
2946 if (FrameHasActiveCall(this))
2947 return PTR_HOST_MEMBER_TADDR(InlinedCallFrame, this,
2948 m_pCallerReturnAddress);
2949 else
2950 return NULL;
2951 }
2952
2953 virtual BOOL NeedsUpdateRegDisplay()
2954 {
2955 WRAPPER_NO_CONTRACT;
2956 return FrameHasActiveCall(this);
2957 }
2958
2959 // Given a methodDesc representing an ILStub for a pinvoke call,
2960 // this method will return the MethodDesc for the actual interop
2961 // method if the current InlinedCallFrame is inactive.
2962 PTR_MethodDesc GetActualInteropMethodDesc()
2963 {
2964#if defined(_TARGET_X86_) || defined(_TARGET_ARM_)
2965 // Important: This code relies on the way JIT lays out frames. Keep it in sync
2966 // with code:Compiler.lvaAssignFrameOffsets.
2967 //
2968 // | ... |
2969 // +--------------------+
2970 // | lvaStubArgumentVar | <= filled with EAX in prolog |
2971 // +--------------------+ |
2972 // | | |
2973 // | InlinedCallFrame | |
2974 // | | <= m_pCrawl.pFrame | to lower addresses
2975 // +--------------------+ V
2976 // | ... |
2977 //
2978 // Extract the actual MethodDesc to report from the InlinedCallFrame.
2979 TADDR addr = dac_cast<TADDR>(this) + sizeof(InlinedCallFrame);
2980 return PTR_MethodDesc(*PTR_TADDR(addr));
2981#elif defined(_WIN64)
2982 // On 64bit, the actual interop MethodDesc is saved off in a field off the InlinedCrawlFrame
2983 // which is populated by the JIT. Refer to JIT_InitPInvokeFrame for details.
2984 return PTR_MethodDesc(m_StubSecretArg);
2985#else
2986 _ASSERTE(!"NYI - Interop method reporting for this architecture!");
2987 return NULL;
2988#endif // defined(_TARGET_X86_) || defined(_TARGET_ARM_)
2989 }
2990
2991 virtual void UpdateRegDisplay(const PREGDISPLAY);
2992
2993 // m_Datum contains MethodDesc ptr or
2994 // - on AMD64: CALLI target address (if lowest bit is set)
2995 // - on X86: argument stack size (if value is <64k)
2996 // See code:HasFunction.
2997 PTR_NDirectMethodDesc m_Datum;
2998
2999#ifdef _WIN64
3000 // IL stubs fill this field with the incoming secret argument when they erect
3001 // InlinedCallFrame so we know which interop method was invoked even if the frame
3002 // is not active at the moment.
3003 PTR_VOID m_StubSecretArg;
3004#endif // _WIN64
3005
3006protected:
3007 // X86: ESP after pushing the outgoing arguments, and just before calling
3008 // out to unmanaged code.
3009 // Other platforms: the field stays set throughout the declaring method.
3010 PTR_VOID m_pCallSiteSP;
3011
3012 // EIP where the unmanaged call will return to. This will be a pointer into
3013 // the code of the managed frame which has the InlinedCallFrame
3014 // This is set to NULL in the method prolog. It gets set just before the
3015 // call to the target and reset back to NULL after the stop-for-GC check
3016 // following the call.
3017 TADDR m_pCallerReturnAddress;
3018
3019 // This is used only for EBP. Hence, a stackwalk will miss the other
3020 // callee-saved registers for the method with the InlinedCallFrame.
3021 // To prevent GC-holes, we do not keep any GC references in callee-saved
3022 // registers across an NDirect call.
3023 TADDR m_pCalleeSavedFP;
3024
3025public:
3026 //---------------------------------------------------------------
3027 // Expose key offsets and values for stub generation.
3028 //---------------------------------------------------------------
3029
3030 static void GetEEInfo(CORINFO_EE_INFO::InlinedCallFrameInfo * pEEInfo);
3031
3032 // Is the specified frame an InlinedCallFrame which has an active call
3033 // inside it right now?
3034 static BOOL FrameHasActiveCall(Frame *pFrame)
3035 {
3036 WRAPPER_NO_CONTRACT;
3037 SUPPORTS_DAC;
3038 return pFrame &&
3039 pFrame != FRAME_TOP &&
3040 InlinedCallFrame::GetMethodFrameVPtr() == pFrame->GetVTablePtr() &&
3041 dac_cast<TADDR>(dac_cast<PTR_InlinedCallFrame>(pFrame)->m_pCallerReturnAddress) != NULL;
3042 }
3043
3044 // Marks the frame as inactive.
3045 void Reset()
3046 {
3047 m_pCallerReturnAddress = NULL;
3048 }
3049
3050 int GetFrameType()
3051 {
3052 LIMITED_METHOD_DAC_CONTRACT;
3053 return TYPE_EXIT;
3054 }
3055
3056 virtual BOOL IsTransitionToNativeFrame()
3057 {
3058 LIMITED_METHOD_CONTRACT;
3059 return TRUE;
3060 }
3061
3062 PTR_VOID GetCallSiteSP()
3063 {
3064 LIMITED_METHOD_CONTRACT;
3065 return m_pCallSiteSP;
3066 }
3067
3068 TADDR GetCalleeSavedFP()
3069 {
3070 LIMITED_METHOD_DAC_CONTRACT;
3071 return m_pCalleeSavedFP;
3072 }
3073
3074 // Set the vptr and GSCookie
3075 VOID Init();
3076
3077 // Keep as last entry in class
3078 DEFINE_VTABLE_GETTER_AND_CTOR_AND_DTOR(InlinedCallFrame)
3079};
3080
3081//------------------------------------------------------------------------
3082// This frame is used to mark a Context/AppDomain Transition
3083//------------------------------------------------------------------------
3084
3085class ContextTransitionFrame : public Frame
3086{
3087private:
3088 PTR_Object m_LastThrownObjectInParentContext;
3089 ULONG_PTR m_LockCount; // Number of locks the thread takes
3090 // before the transition.
3091 VPTR_VTABLE_CLASS(ContextTransitionFrame, Frame)
3092
3093public:
3094 virtual void GcScanRoots(promote_func *fn, ScanContext* sc);
3095
3096 OBJECTREF GetLastThrownObjectInParentContext()
3097 {
3098 return ObjectToOBJECTREF(m_LastThrownObjectInParentContext);
3099 }
3100
3101 void SetLastThrownObjectInParentContext(OBJECTREF lastThrownObject)
3102 {
3103 m_LastThrownObjectInParentContext = OBJECTREFToObject(lastThrownObject);
3104 }
3105
3106 void SetLockCount(DWORD lockCount)
3107 {
3108 LIMITED_METHOD_CONTRACT;
3109 m_LockCount = lockCount;
3110 }
3111 DWORD GetLockCount()
3112 {
3113 LIMITED_METHOD_CONTRACT;
3114 return (DWORD) m_LockCount;
3115 }
3116
3117
3118 // Let debugger know that we're transitioning between AppDomains.
3119 ETransitionType GetTransitionType()
3120 {
3121 LIMITED_METHOD_DAC_CONTRACT;
3122 return TT_AppDomain;
3123 }
3124
3125#ifndef DACCESS_COMPILE
3126 ContextTransitionFrame()
3127 : m_LastThrownObjectInParentContext(NULL)
3128 , m_LockCount(0)
3129 {
3130 LIMITED_METHOD_CONTRACT;
3131 }
3132#endif
3133
3134 // Keep as last entry in class
3135 DEFINE_VTABLE_GETTER_AND_DTOR(ContextTransitionFrame)
3136};
3137
3138// TODO [DAVBR]: For the full fix for VsWhidbey 450273, this
3139// may be uncommented once isLegalManagedCodeCaller works properly
3140// with non-return address inputs, and with non-DEBUG builds
3141//bool isLegalManagedCodeCaller(TADDR retAddr);
3142bool isRetAddr(TADDR retAddr, TADDR* whereCalled);
3143
3144//------------------------------------------------------------------------
3145#ifdef _TARGET_X86_
3146// This frame is used as padding for virtual stub dispatch tailcalls.
3147// When A calls B via virtual stub dispatch, the stub dispatch stub resolves
3148// the target code for B and jumps to it. If A wants to do a tail call,
3149// it does not get a chance to unwind its frame since the virtual stub dispatch
3150// stub is not set up to return the address of the target code (rather
3151// than just jumping to it).
3152// To do a tail call, A calls JIT_TailCall, which unwinds A's frame
3153// and sets up a TailCallFrame. It then calls the stub dispatch stub
3154// which disassembles the caller (JIT_TailCall, in this case) to get some information,
3155// resolves the target code for B, and then jumps to B.
3156// If B also does a virtual stub dispatch tail call, then we reuse the
3157// existing TailCallFrame instead of setting up a second one.
3158//
3159// We could eliminate TailCallFrame if we factor the VSD stub to return
3160// the target code address. This is currently not a very important scenario
3161// as tail calls on interface calls are uncommon.
3162#else
3163// This frame is used as padding for tailcalls which require more space
3164// than the caller has in it's incoming argument space.
3165// To do a tail call from A to B, A calls JIT_TailCall, which unwinds A's frame
3166// and sets up a TailCallFrame and the arguments. It then jumps to B.
3167// If B also does a tail call, then we reuse the
3168// existing TailCallFrame instead of setting up a second one.
3169//
3170// This is also used whenever value types that aren't enregisterable are
3171// passed by value instead of ref. This is currently not a very important
3172// scenario as tail calls are uncommon.
3173#endif
3174//------------------------------------------------------------------------
3175
3176class TailCallFrame : public Frame
3177{
3178 VPTR_VTABLE_CLASS(TailCallFrame, Frame)
3179
3180#if defined(_TARGET_X86_)
3181 TADDR m_CallerAddress; // the address the tailcall was initiated from
3182 CalleeSavedRegisters m_regs; // callee saved registers - the stack walk assumes that all non-JIT frames have them
3183 TADDR m_ReturnAddress; // the return address of the tailcall
3184#elif defined(_TARGET_AMD64_)
3185 TADDR m_pGCLayout;
3186 TADDR m_padding; // code:StubLinkerCPU::CreateTailCallCopyArgsThunk expects the size of TailCallFrame to be 16-byte aligned
3187 CalleeSavedRegisters m_calleeSavedRegisters;
3188 TADDR m_ReturnAddress;
3189#elif defined(_TARGET_ARM_)
3190 union {
3191 CalleeSavedRegisters m_calleeSavedRegisters;
3192 // alias saved link register as m_ReturnAddress
3193 struct {
3194 INT32 r4, r5, r6, r7, r8, r9, r10;
3195 INT32 r11;
3196 TADDR m_ReturnAddress;
3197 };
3198 };
3199#else
3200 TADDR m_ReturnAddress;
3201#endif
3202
3203public:
3204#ifndef CROSSGEN_COMPILE
3205#if !defined(_TARGET_X86_)
3206
3207#ifndef DACCESS_COMPILE
3208 TailCallFrame(T_CONTEXT * pContext, Thread * pThread)
3209 {
3210 InitFromContext(pContext);
3211 m_Next = pThread->GetFrame();
3212 }
3213
3214 void InitFromContext(T_CONTEXT * pContext);
3215
3216 // Architecture-specific method to initialize a CONTEXT record as if the first
3217 // part of the TailCallHelperStub had executed
3218 static TailCallFrame * AdjustContextForTailCallHelperStub(_CONTEXT * pContext, size_t cbNewArgArea, Thread * pThread);
3219#endif
3220
3221 static TailCallFrame * GetFrameFromContext(CONTEXT * pContext);
3222#endif // !_TARGET_X86_
3223
3224#if defined(_TARGET_X86_)
3225 static TailCallFrame* FindTailCallFrame(Frame* pFrame)
3226 {
3227 LIMITED_METHOD_CONTRACT;
3228 // loop through the frame chain
3229 while (pFrame->GetVTablePtr() != TailCallFrame::GetMethodFrameVPtr())
3230 pFrame = pFrame->m_Next;
3231 return (TailCallFrame*)pFrame;
3232 }
3233
3234 TADDR GetCallerAddress()
3235 {
3236 LIMITED_METHOD_CONTRACT;
3237 return m_CallerAddress;
3238 }
3239#endif // _TARGET_X86_
3240
3241 virtual TADDR GetReturnAddressPtr()
3242 {
3243 LIMITED_METHOD_DAC_CONTRACT;
3244 return PTR_HOST_MEMBER_TADDR(TailCallFrame, this,
3245 m_ReturnAddress);
3246 }
3247
3248 virtual BOOL NeedsUpdateRegDisplay()
3249 {
3250 return TRUE;
3251 }
3252
3253 virtual void UpdateRegDisplay(const PREGDISPLAY pRD);
3254#endif // !CROSSGEN_COMPILE
3255#ifdef _TARGET_AMD64_
3256 void SetGCLayout(TADDR pGCLayout)
3257 {
3258 LIMITED_METHOD_CONTRACT;
3259 m_pGCLayout = pGCLayout;
3260 }
3261
3262 virtual void GcScanRoots(promote_func *fn, ScanContext* sc);
3263#else
3264 void SetGCLayout(TADDR pGCLayout)
3265 {
3266 LIMITED_METHOD_CONTRACT;
3267 _ASSERTE(pGCLayout == NULL);
3268 }
3269#endif
3270
3271private:
3272 // Keep as last entry in class
3273 DEFINE_VTABLE_GETTER_AND_CTOR_AND_DTOR(TailCallFrame)
3274};
3275
3276//------------------------------------------------------------------------
3277// ExceptionFilterFrame is a small frame whose only purpose in
3278// life is to set SHADOW_SP_FILTER_DONE during unwind from exception filter.
3279//------------------------------------------------------------------------
3280
3281class ExceptionFilterFrame : public Frame
3282{
3283 VPTR_VTABLE_CLASS(ExceptionFilterFrame, Frame)
3284 size_t* m_pShadowSP;
3285
3286public:
3287#ifndef DACCESS_COMPILE
3288 ExceptionFilterFrame(size_t* pShadowSP)
3289 {
3290 WRAPPER_NO_CONTRACT;
3291 m_pShadowSP = pShadowSP;
3292 Push();
3293 }
3294
3295 void Pop()
3296 {
3297 // Nothing to do here.
3298 WRAPPER_NO_CONTRACT;
3299 SetFilterDone();
3300 Frame::Pop();
3301 }
3302
3303 void SetFilterDone()
3304 {
3305 LIMITED_METHOD_CONTRACT;
3306
3307 // Mark the filter as having completed
3308 if (m_pShadowSP)
3309 {
3310 // Make sure that CallJitEHFilterHelper marked us as being in the filter.
3311 _ASSERTE(*m_pShadowSP & ICodeManager::SHADOW_SP_IN_FILTER);
3312 *m_pShadowSP |= ICodeManager::SHADOW_SP_FILTER_DONE;
3313 }
3314 }
3315#endif
3316
3317private:
3318 // Keep as last entry in class
3319 DEFINE_VTABLE_GETTER_AND_CTOR_AND_DTOR(ExceptionFilterFrame)
3320};
3321
3322#ifdef _DEBUG
3323// We use IsProtectedByGCFrame to check if some OBJECTREF pointers are protected
3324// against GC. That function doesn't know if a byref is from managed stack thus
3325// protected by JIT. AssumeByrefFromJITStack is used to bypass that check if an
3326// OBJECTRef pointer is passed from managed code to an FCall and it's in stack.
3327class AssumeByrefFromJITStack : public Frame
3328{
3329 VPTR_VTABLE_CLASS(AssumeByrefFromJITStack, Frame)
3330public:
3331#ifndef DACCESS_COMPILE
3332 AssumeByrefFromJITStack(OBJECTREF *pObjRef)
3333 {
3334 m_pObjRef = pObjRef;
3335 }
3336#endif
3337
3338 BOOL Protects(OBJECTREF *ppORef)
3339 {
3340 LIMITED_METHOD_CONTRACT;
3341 return ppORef == m_pObjRef;
3342 }
3343
3344private:
3345 OBJECTREF *m_pObjRef;
3346
3347 // Keep as last entry in class
3348 DEFINE_VTABLE_GETTER_AND_DTOR(AssumeByrefFromJITStack)
3349}; //AssumeByrefFromJITStack
3350
3351#endif //_DEBUG
3352
3353//-----------------------------------------------------------------------------
3354// FrameWithCookie is used to declare a Frame in source code with a cookie
3355// immediately preceeding it.
3356// This is just a specialized version of GSCookieFor<T>
3357//
3358// For Frames that are set up by stubs, the stub is responsible for setting up
3359// the GSCookie.
3360//
3361// Note that we have to play all these games for the GSCookie as the GSCookie
3362// needs to precede the vtable pointer, so that the GSCookie is guaranteed to
3363// catch any stack-buffer-overrun corruptions that overwrite the Frame data.
3364//
3365//-----------------------------------------------------------------------------
3366
3367class DebuggerEval;
3368
3369class GCSafeCollection;
3370
3371template <typename FrameType>
3372class FrameWithCookie
3373{
3374protected:
3375
3376 GSCookie m_gsCookie;
3377 FrameType m_frame;
3378
3379public:
3380
3381 //
3382 // Overload all the required constructors
3383 //
3384
3385 FrameWithCookie() :
3386 m_gsCookie(GetProcessGSCookie()), m_frame() { WRAPPER_NO_CONTRACT; }
3387
3388 FrameWithCookie(Thread * pThread) :
3389 m_gsCookie(GetProcessGSCookie()), m_frame(pThread) { WRAPPER_NO_CONTRACT; }
3390
3391 FrameWithCookie(T_CONTEXT * pContext) :
3392 m_gsCookie(GetProcessGSCookie()), m_frame(pContext) { WRAPPER_NO_CONTRACT; }
3393
3394 FrameWithCookie(TransitionBlock * pTransitionBlock) :
3395 m_gsCookie(GetProcessGSCookie()), m_frame(pTransitionBlock) { WRAPPER_NO_CONTRACT; }
3396
3397 FrameWithCookie(TransitionBlock * pTransitionBlock, MethodDesc * pMD) :
3398 m_gsCookie(GetProcessGSCookie()), m_frame(pTransitionBlock, pMD) { WRAPPER_NO_CONTRACT; }
3399
3400 FrameWithCookie(TransitionBlock * pTransitionBlock, VASigCookie * pVASigCookie, PCODE pUnmanagedTarget) :
3401 m_gsCookie(GetProcessGSCookie()), m_frame(pTransitionBlock, pVASigCookie, pUnmanagedTarget) { WRAPPER_NO_CONTRACT; }
3402
3403 FrameWithCookie(TransitionBlock * pTransitionBlock, int frameFlags) :
3404 m_gsCookie(GetProcessGSCookie()), m_frame(pTransitionBlock, frameFlags) { WRAPPER_NO_CONTRACT; }
3405
3406
3407 // GCFrame
3408 FrameWithCookie(Thread * pThread, OBJECTREF *pObjRefs, UINT numObjRefs, BOOL maybeInterior) :
3409 m_gsCookie(GetProcessGSCookie()), m_frame(pThread, pObjRefs, numObjRefs, maybeInterior) { WRAPPER_NO_CONTRACT; }
3410
3411 FrameWithCookie(OBJECTREF *pObjRefs, UINT numObjRefs, BOOL maybeInterior) :
3412 m_gsCookie(GetProcessGSCookie()), m_frame(pObjRefs, numObjRefs, maybeInterior) { WRAPPER_NO_CONTRACT; }
3413
3414 // GCSafeCollectionFrame
3415 FrameWithCookie(GCSafeCollection *gcSafeCollection) :
3416 m_gsCookie(GetProcessGSCookie()), m_frame(gcSafeCollection) { WRAPPER_NO_CONTRACT; }
3417
3418#ifdef FEATURE_INTERPRETER
3419 // InterpreterFrame
3420 FrameWithCookie(Interpreter* interp) :
3421 m_gsCookie(GetProcessGSCookie()), m_frame(interp) { WRAPPER_NO_CONTRACT; }
3422#endif
3423
3424 // HijackFrame
3425 FrameWithCookie(LPVOID returnAddress, Thread *thread, HijackArgs *args) :
3426 m_gsCookie(GetProcessGSCookie()), m_frame(returnAddress, thread, args) { WRAPPER_NO_CONTRACT; }
3427
3428#ifdef DEBUGGING_SUPPORTED
3429 // FuncEvalFrame
3430 FrameWithCookie(DebuggerEval *pDebuggerEval, TADDR returnAddress, BOOL showFrame) :
3431 m_gsCookie(GetProcessGSCookie()), m_frame(pDebuggerEval, returnAddress, showFrame) { WRAPPER_NO_CONTRACT; }
3432#endif // DEBUGGING_SUPPORTED
3433
3434 // TailCallFrame
3435 FrameWithCookie(T_CONTEXT * pContext, Thread *thread) :
3436 m_gsCookie(GetProcessGSCookie()), m_frame(pContext, thread) { WRAPPER_NO_CONTRACT; }
3437
3438#ifndef DACCESS_COMPILE
3439 // GSCookie for HelperMethodFrames is initialized in a common HelperMethodFrame init method
3440
3441 // HelperMethodFrame
3442 FORCEINLINE FrameWithCookie(void* fCallFtnEntry, unsigned attribs = 0) :
3443 m_frame(fCallFtnEntry, attribs) { WRAPPER_NO_CONTRACT; }
3444
3445 // HelperMethodFrame_1OBJ
3446 FORCEINLINE FrameWithCookie(void* fCallFtnEntry, unsigned attribs, OBJECTREF * aGCPtr1) :
3447 m_frame(fCallFtnEntry, attribs, aGCPtr1) { WRAPPER_NO_CONTRACT; }
3448
3449 // HelperMethodFrame_2OBJ
3450 FORCEINLINE FrameWithCookie(void* fCallFtnEntry, unsigned attribs, OBJECTREF * aGCPtr1, OBJECTREF * aGCPtr2) :
3451 m_frame(fCallFtnEntry, attribs, aGCPtr1, aGCPtr2) { WRAPPER_NO_CONTRACT; }
3452
3453 // HelperMethodFrame_3OBJ
3454 FORCEINLINE FrameWithCookie(void* fCallFtnEntry, unsigned attribs, OBJECTREF * aGCPtr1, OBJECTREF * aGCPtr2, OBJECTREF * aGCPtr3) :
3455 m_frame(fCallFtnEntry, attribs, aGCPtr1, aGCPtr2, aGCPtr3) { WRAPPER_NO_CONTRACT; }
3456
3457 // HelperMethodFrame_PROTECTOBJ
3458 FORCEINLINE FrameWithCookie(void* fCallFtnEntry, unsigned attribs, OBJECTREF* pObjRefs, int numObjRefs) :
3459 m_frame(fCallFtnEntry, attribs, pObjRefs, numObjRefs) { WRAPPER_NO_CONTRACT; }
3460
3461#endif // DACCESS_COMPILE
3462
3463 // ProtectByRefsFrame
3464 FrameWithCookie(Thread * pThread, ByRefInfo * pByRefs) :
3465 m_gsCookie(GetProcessGSCookie()), m_frame(pThread, pByRefs) { WRAPPER_NO_CONTRACT; }
3466
3467 // ProtectValueClassFrame
3468 FrameWithCookie(Thread * pThread, ValueClassInfo * pValueClasses) :
3469 m_gsCookie(GetProcessGSCookie()), m_frame(pThread, pValueClasses) { WRAPPER_NO_CONTRACT; }
3470
3471 // ExceptionFilterFrame
3472 FrameWithCookie(size_t* pShadowSP) :
3473 m_gsCookie(GetProcessGSCookie()), m_frame(pShadowSP) { WRAPPER_NO_CONTRACT; }
3474
3475#ifdef _DEBUG
3476 // AssumeByrefFromJITStack
3477 FrameWithCookie(OBJECTREF *pObjRef) :
3478 m_gsCookie(GetProcessGSCookie()), m_frame(pObjRef) { WRAPPER_NO_CONTRACT; }
3479
3480 void SetAddrOfHaveCheckedRestoreState(BOOL* pDoneCheck)
3481 {
3482 WRAPPER_NO_CONTRACT;
3483 m_frame.SetAddrOfHaveCheckedRestoreState(pDoneCheck);
3484 }
3485
3486#endif //_DEBUG
3487
3488 //
3489 // Overload some common Frame methods for easy redirection
3490 //
3491
3492 void Push() { WRAPPER_NO_CONTRACT; m_frame.Push(); }
3493 void Pop() { WRAPPER_NO_CONTRACT; m_frame.Pop(); }
3494 void Push(Thread * pThread) { WRAPPER_NO_CONTRACT; m_frame.Push(pThread); }
3495 void Pop(Thread * pThread) { WRAPPER_NO_CONTRACT; m_frame.Pop(pThread); }
3496 PCODE GetReturnAddress() { WRAPPER_NO_CONTRACT; return m_frame.GetReturnAddress(); }
3497 T_CONTEXT * GetContext() { WRAPPER_NO_CONTRACT; return m_frame.GetContext(); }
3498 FrameType* operator&() { LIMITED_METHOD_CONTRACT; return &m_frame; }
3499 LazyMachState * MachineState() { WRAPPER_NO_CONTRACT; return m_frame.MachineState(); }
3500 Thread * GetThread() { WRAPPER_NO_CONTRACT; return m_frame.GetThread(); }
3501 BOOL InsureInit(bool initialInit, struct MachState* unwindState)
3502 { WRAPPER_NO_CONTRACT; return m_frame.InsureInit(initialInit, unwindState); }
3503 void Poll() { WRAPPER_NO_CONTRACT; m_frame.Poll(); }
3504 void SetStackPointerPtr(TADDR sp) { WRAPPER_NO_CONTRACT; m_frame.SetStackPointerPtr(sp); }
3505 void InitAndLink(T_CONTEXT *pContext) { WRAPPER_NO_CONTRACT; m_frame.InitAndLink(pContext); }
3506 void Init(Thread *pThread, OBJECTREF *pObjRefs, UINT numObjRefs, BOOL maybeInterior)
3507 { WRAPPER_NO_CONTRACT; m_frame.Init(pThread, pObjRefs, numObjRefs, maybeInterior); }
3508 ValueClassInfo ** GetValueClassInfoList() { WRAPPER_NO_CONTRACT; return m_frame.GetValueClassInfoList(); }
3509
3510#if 0
3511 //
3512 // Access to the underlying Frame
3513 // You should only need to use this if none of the above overloads work for you
3514 // Consider adding the required overload to the list above
3515 //
3516
3517 FrameType& operator->() { LIMITED_METHOD_CONTRACT; return m_frame; }
3518#endif
3519
3520 // Since the "&" operator is overloaded, use this function to get to the
3521 // address of FrameWithCookie, rather than that of FrameWithCookie::m_frame.
3522 GSCookie * GetGSCookiePtr() { LIMITED_METHOD_CONTRACT; return &m_gsCookie; }
3523};
3524
3525//------------------------------------------------------------------------
3526// These macros GC-protect OBJECTREF pointers on the EE's behalf.
3527// In between these macros, the GC can move but not discard the protected
3528// objects. If the GC moves an object, it will update the guarded OBJECTREF's.
3529// Typical usage:
3530//
3531// OBJECTREF or = <some valid objectref>;
3532// GCPROTECT_BEGIN(or);
3533//
3534// ...<do work that can trigger GC>...
3535//
3536// GCPROTECT_END();
3537//
3538//
3539// These macros can also protect multiple OBJECTREF's if they're packaged
3540// into a structure:
3541//
3542// struct xx {
3543// OBJECTREF o1;
3544// OBJECTREF o2;
3545// } gc;
3546//
3547// GCPROTECT_BEGIN(gc);
3548// ....
3549// GCPROTECT_END();
3550//
3551//
3552// Notes:
3553//
3554// - GCPROTECT_BEGININTERIOR() can be used in place of GCPROTECT_BEGIN()
3555// to handle the case where one or more of the OBJECTREFs is potentially
3556// an interior pointer. This is a rare situation, because boxing would
3557// normally prevent us from encountering it. Be aware that the OBJECTREFs
3558// we protect are not validated in this situation.
3559//
3560// - GCPROTECT_ARRAY_BEGIN() can be used when an array of object references
3561// is allocated on the stack. The pointer to the first element is passed
3562// along with the number of elements in the array.
3563//
3564// - The argument to GCPROTECT_BEGIN should be an lvalue because it
3565// uses "sizeof" to count the OBJECTREF's.
3566//
3567// - GCPROTECT_BEGIN spiritually violates our normal convention of not passing
3568// non-const refernce arguments. Unfortunately, this is necessary in
3569// order for the sizeof thing to work.
3570//
3571// - GCPROTECT_BEGIN does _not_ zero out the OBJECTREF's. You must have
3572// valid OBJECTREF's when you invoke this macro.
3573//
3574// - GCPROTECT_BEGIN begins a new C nesting block. Besides allowing
3575// GCPROTECT_BEGIN's to nest, it also has the advantage of causing
3576// a compiler error if you forget to code a maching GCPROTECT_END.
3577//
3578// - If you are GCPROTECTing something, it means you are expecting a GC to occur.
3579// So we assert that GC is not forbidden. If you hit this assert, you probably need
3580// a HELPER_METHOD_FRAME to protect the region that can cause the GC.
3581//------------------------------------------------------------------------
3582
3583#ifndef DACCESS_COMPILE
3584
3585#ifdef _PREFAST_
3586// Suppress prefast warning #6384: Dividing sizeof a pointer by another value
3587#pragma warning(disable:6384)
3588#endif /*_PREFAST_ */
3589
3590#define GCPROTECT_BEGIN(ObjRefStruct) do { \
3591 FrameWithCookie<GCFrame> __gcframe( \
3592 (OBJECTREF*)&(ObjRefStruct), \
3593 sizeof(ObjRefStruct)/sizeof(OBJECTREF), \
3594 FALSE); \
3595 /* work around unreachable code warning */ \
3596 if (true) { DEBUG_ASSURE_NO_RETURN_BEGIN(GCPROTECT)
3597
3598#define GCPROTECT_BEGIN_THREAD(pThread, ObjRefStruct) do { \
3599 FrameWithCookie<GCFrame> __gcframe( \
3600 pThread, \
3601 (OBJECTREF*)&(ObjRefStruct), \
3602 sizeof(ObjRefStruct)/sizeof(OBJECTREF), \
3603 FALSE); \
3604 /* work around unreachable code warning */ \
3605 if (true) { DEBUG_ASSURE_NO_RETURN_BEGIN(GCPROTECT)
3606
3607#define GCPROTECT_ARRAY_BEGIN(ObjRefArray,cnt) do { \
3608 FrameWithCookie<GCFrame> __gcframe( \
3609 (OBJECTREF*)&(ObjRefArray), \
3610 cnt * sizeof(ObjRefArray) / sizeof(OBJECTREF), \
3611 FALSE); \
3612 /* work around unreachable code warning */ \
3613 if (true) { DEBUG_ASSURE_NO_RETURN_BEGIN(GCPROTECT)
3614
3615#define GCPROTECT_BEGININTERIOR(ObjRefStruct) do { \
3616 FrameWithCookie<GCFrame> __gcframe( \
3617 (OBJECTREF*)&(ObjRefStruct), \
3618 sizeof(ObjRefStruct)/sizeof(OBJECTREF), \
3619 TRUE); \
3620 /* work around unreachable code warning */ \
3621 if (true) { DEBUG_ASSURE_NO_RETURN_BEGIN(GCPROTECT)
3622
3623#define GCPROTECT_BEGININTERIOR_ARRAY(ObjRefArray,cnt) do { \
3624 FrameWithCookie<GCFrame> __gcframe( \
3625 (OBJECTREF*)&(ObjRefArray), \
3626 cnt, \
3627 TRUE); \
3628 /* work around unreachable code warning */ \
3629 if (true) { DEBUG_ASSURE_NO_RETURN_BEGIN(GCPROTECT)
3630
3631
3632#define GCPROTECT_END() \
3633 DEBUG_ASSURE_NO_RETURN_END(GCPROTECT) } \
3634 __gcframe.Pop(); } while(0)
3635
3636
3637#else // #ifndef DACCESS_COMPILE
3638
3639#define GCPROTECT_BEGIN(ObjRefStruct)
3640#define GCPROTECT_ARRAY_BEGIN(ObjRefArray,cnt)
3641#define GCPROTECT_BEGININTERIOR(ObjRefStruct)
3642#define GCPROTECT_END()
3643
3644#endif // #ifndef DACCESS_COMPILE
3645
3646
3647#define ASSERT_ADDRESS_IN_STACK(address) _ASSERTE (Thread::IsAddressInCurrentStack (address));
3648
3649#if defined (_DEBUG) && !defined (DACCESS_COMPILE)
3650#define ASSUME_BYREF_FROM_JIT_STACK_BEGIN(__objRef) \
3651 /* make sure we are only called inside an FCall */ \
3652 if (__me == 0) {}; \
3653 /* make sure the address is in stack. If the address is an interior */ \
3654 /*pointer points to GC heap, the FCall still needs to protect it explicitly */ \
3655 ASSERT_ADDRESS_IN_STACK (__objRef); \
3656 do { \
3657 FrameWithCookie<AssumeByrefFromJITStack> __dummyAssumeByrefFromJITStack ((__objRef)); \
3658 __dummyAssumeByrefFromJITStack.Push (); \
3659 /* work around unreachable code warning */ \
3660 if (true) { DEBUG_ASSURE_NO_RETURN_BEGIN(GC_PROTECT)
3661
3662#define ASSUME_BYREF_FROM_JIT_STACK_END() \
3663 DEBUG_ASSURE_NO_RETURN_END(GC_PROTECT) } \
3664 __dummyAssumeByrefFromJITStack.Pop(); } while(0)
3665#else //defined (_DEBUG) && !defined (DACCESS_COMPILE)
3666#define ASSUME_BYREF_FROM_JIT_STACK_BEGIN(__objRef)
3667#define ASSUME_BYREF_FROM_JIT_STACK_END()
3668#endif //defined (_DEBUG) && !defined (DACCESS_COMPILE)
3669
3670//------------------------------------------------------------------------
3671
3672#if defined(FRAMES_TURNED_FPO_ON)
3673#pragma optimize("", on) // Go back to command line default optimizations
3674#undef FRAMES_TURNED_FPO_ON
3675#undef FPO_ON
3676#endif
3677
3678#endif //__frames_h__
3679