Fix the explicit frames unwinding on Unix
[platform/upstream/coreclr.git] / src / vm / frames.cpp
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.CPP
5
6
7
8 #include "common.h"
9 #include "log.h"
10 #include "frames.h"
11 #include "threads.h"
12 #include "object.h"
13 #include "method.hpp"
14 #include "class.h"
15 #include "excep.h"
16 #include "security.h"
17 #include "stublink.h"
18 #include "fieldmarshaler.h"
19 #include "objecthandle.h"
20 #include "siginfo.hpp"
21 #include "gc.h"
22 #include "dllimportcallback.h"
23 #include "stackwalk.h"
24 #include "dbginterface.h"
25 #include "gms.h"
26 #include "eeconfig.h"
27 #ifdef FEATURE_REMOTING
28 #include "remoting.h"
29 #endif
30 #include "ecall.h"
31 #include "clsload.hpp"
32 #include "cgensys.h"
33 #include "virtualcallstub.h"
34 #include "mdaassistants.h"
35 #include "dllimport.h"
36 #include "gcrefmap.h"
37 #include "asmconstants.h"
38
39 #ifdef FEATURE_COMINTEROP
40 #include "comtoclrcall.h"
41 #endif // FEATURE_COMINTEROP
42
43 #ifdef FEATURE_INTERPRETER
44 #include "interpreter.h"
45 #endif // FEATURE_INTERPRETER
46
47 #include "argdestination.h"
48
49 #if CHECK_APP_DOMAIN_LEAKS
50 #define CHECK_APP_DOMAIN    GC_CALL_CHECK_APP_DOMAIN
51 #else
52 #define CHECK_APP_DOMAIN    0
53 #endif
54
55 //-----------------------------------------------------------------------
56 #if _DEBUG
57 //-----------------------------------------------------------------------
58
59 #ifndef DACCESS_COMPILE
60
61 unsigned dbgStubCtr = 0;
62 unsigned dbgStubTrip = 0xFFFFFFFF;
63
64 void Frame::Log() {
65     WRAPPER_NO_CONTRACT;
66
67     if (!LoggingOn(LF_STUBS, LL_INFO1000000))
68         return;
69
70     dbgStubCtr++;
71     if (dbgStubCtr > dbgStubTrip) {
72         dbgStubCtr++;      // basicly a nop to put a breakpoint on.
73     }
74
75     MethodDesc* method = GetFunction();
76
77 #ifdef _TARGET_X86_
78     if (GetVTablePtr() == UMThkCallFrame::GetMethodFrameVPtr())
79         method = ((UMThkCallFrame*) this)->GetUMEntryThunk()->GetMethod();
80 #endif
81
82     STRESS_LOG3(LF_STUBS, LL_INFO1000000, "STUBS: In Stub with Frame %p assoc Method %pM FrameType = %pV\n", this, method, *((void**) this));
83
84     char buff[64];
85     const char* frameType;
86     if (GetVTablePtr() == PrestubMethodFrame::GetMethodFrameVPtr())
87         frameType = "PreStub";
88 #ifdef _TARGET_X86_
89     else if (GetVTablePtr() == UMThkCallFrame::GetMethodFrameVPtr())
90         frameType = "UMThkCallFrame";
91 #endif
92     else if (GetVTablePtr() == PInvokeCalliFrame::GetMethodFrameVPtr()) 
93     {
94         sprintf_s(buff, COUNTOF(buff), "PInvoke CALLI target" FMT_ADDR,
95                   DBG_ADDR(((PInvokeCalliFrame*)this)->GetPInvokeCalliTarget()));
96         frameType = buff;
97     }
98     else if (GetVTablePtr() == StubDispatchFrame::GetMethodFrameVPtr())
99         frameType = "StubDispatch";
100     else if (GetVTablePtr() == ExternalMethodFrame::GetMethodFrameVPtr())
101         frameType = "ExternalMethod";
102     else 
103         frameType = "Unknown";
104
105     if (method != 0)
106         LOG((LF_STUBS, LL_INFO1000000, 
107              "IN %s Stub Method = %s::%s SIG %s ESP of return" FMT_ADDR "\n",
108              frameType, 
109              method->m_pszDebugClassName,
110              method->m_pszDebugMethodName,
111              method->m_pszDebugMethodSignature,
112              DBG_ADDR(GetReturnAddressPtr())));
113     else 
114         LOG((LF_STUBS, LL_INFO1000000, 
115              "IN %s Stub Method UNKNOWN ESP of return" FMT_ADDR "\n", 
116              frameType, 
117              DBG_ADDR(GetReturnAddressPtr()) ));
118
119     _ASSERTE(GetThread()->PreemptiveGCDisabled());
120 }
121
122 //-----------------------------------------------------------------------
123 // This function is used to log transitions in either direction 
124 // between unmanaged code and CLR/managed code.
125 // This is typically done in a stub that sets up a Frame, which is
126 // passed as an argument to this function.
127
128 void __stdcall Frame::LogTransition(Frame* frame)
129 {
130
131     CONTRACTL {
132         DEBUG_ONLY;
133         NOTHROW;
134         ENTRY_POINT;
135         GC_NOTRIGGER;
136     } CONTRACTL_END;
137
138     BEGIN_ENTRYPOINT_VOIDRET;
139
140 #ifdef _TARGET_X86_
141     // On x86, StubLinkerCPU::EmitMethodStubProlog calls Frame::LogTransition
142     // but the caller of EmitMethodStubProlog sets the GSCookie later on.
143     // So the cookie is not initialized by the point we get here.
144 #else
145     _ASSERTE(*frame->GetGSCookiePtr() == GetProcessGSCookie());
146 #endif
147
148     if (Frame::ShouldLogTransitions())
149         frame->Log();
150
151     END_ENTRYPOINT_VOIDRET;
152 } // void Frame::Log()
153
154 #endif // #ifndef DACCESS_COMPILE
155
156 //-----------------------------------------------------------------------
157 #endif // _DEBUG
158 //-----------------------------------------------------------------------
159
160
161 // TODO [DAVBR]: For the full fix for VsWhidbey 450273, all the below
162 // may be uncommented once isLegalManagedCodeCaller works properly
163 // with non-return address inputs, and with non-DEBUG builds
164 #if 0
165 //-----------------------------------------------------------------------
166 // returns TRUE if retAddr, is a return address that can call managed code
167
168 bool isLegalManagedCodeCaller(PCODE retAddr) {
169     WRAPPER_NO_CONTRACT;
170 #ifdef _TARGET_X86_
171
172         // we expect to be called from JITTED code or from special code sites inside
173         // mscorwks like callDescr which we have put a NOP (0x90) so we know that they
174         // are specially blessed. 
175     if (!ExecutionManager::IsManagedCode(retAddr) &&
176         (
177 #ifdef DACCESS_COMPILE
178          !(PTR_BYTE(retAddr).IsValid()) ||
179 #endif
180          ((*PTR_BYTE(retAddr) != 0x90) &&
181           (*PTR_BYTE(retAddr) != 0xcc))))
182     {
183         LOG((LF_GC, LL_INFO10, "Bad caller to managed code: retAddr=0x%08x, *retAddr=0x%x\n",
184              retAddr, *(BYTE*)PTR_BYTE(retAddr)));
185         
186         return false;
187     }
188
189         // it better be a return address of some kind 
190     TADDR dummy;
191     if (isRetAddr(retAddr, &dummy))
192         return true;
193
194 #ifndef DACCESS_COMPILE
195 #ifdef DEBUGGING_SUPPORTED
196     // The debugger could have dropped an INT3 on the instruction that made the call
197     // Calls can be 2 to 7 bytes long
198     if (CORDebuggerAttached()) {
199         PTR_BYTE ptr = PTR_BYTE(retAddr);
200         for (int i = -2; i >= -7; --i)
201             if (ptr[i] == 0xCC)
202                 return true;
203         return false;
204     }
205 #endif // DEBUGGING_SUPPORTED
206 #endif // #ifndef DACCESS_COMPILE
207
208     _ASSERTE(!"Bad return address on stack");
209     return false;
210 #else  // _TARGET_X86_
211     return true;
212 #endif // _TARGET_X86_
213 }
214 #endif //0
215
216
217 //-----------------------------------------------------------------------
218 // Count of the number of frame types
219 const size_t FRAME_TYPES_COUNT = 
220 #define FRAME_TYPE_NAME(frameType) +1
221 #include "frames.h"
222 ;
223
224 #if defined (_DEBUG_IMPL)   // _DEBUG and !DAC
225
226 //-----------------------------------------------------------------------
227 // Implementation of the global table of names.  On the DAC side, just the global pointer.
228 //  On the runtime side, the array of names.
229     #define FRAME_TYPE_NAME(x) {x::GetMethodFrameVPtr(), #x} ,
230     static FrameTypeName FrameTypeNameTable[] = {
231     #include "frames.h"
232     };
233
234
235 /* static */
236 PTR_CSTR Frame::GetFrameTypeName(TADDR vtbl)
237 {
238     LIMITED_METHOD_CONTRACT;
239     for (size_t i=0; i<FRAME_TYPES_COUNT; ++i)
240     {
241         if (vtbl == FrameTypeNameTable[(int)i].vtbl)
242         {
243             return FrameTypeNameTable[(int)i].name;
244         }
245     }
246
247     return NULL;
248 } // char* Frame::FrameTypeName()
249
250
251 //-----------------------------------------------------------------------
252
253
254 void Frame::LogFrame(
255     int         LF,                     // Log facility for this call.
256     int         LL)                     // Log Level for this call.
257 {
258     char        buf[32];
259     const char  *pFrameType;
260     pFrameType = GetFrameTypeName();
261     
262     if (pFrameType == NULL)
263     {
264         pFrameType = GetFrameTypeName(GetVTablePtr());
265     }
266
267     if (pFrameType == NULL)
268     {
269         _ASSERTE(!"New Frame type needs to be added to FrameTypeName()");
270         // Pointer is up to 17chars + vtbl@ = 22 chars
271         sprintf_s(buf, COUNTOF(buf), "vtbl@%p", GetVTablePtr());
272         pFrameType = buf;
273     }
274
275     LOG((LF, LL, "FRAME: addr:%p, next:%p, type:%s\n",
276          this, m_Next, pFrameType));
277 } // void Frame::LogFrame()
278
279 void Frame::LogFrameChain(
280     int         LF,                     // Log facility for this call.
281     int         LL)                     // Log Level for this call.
282 {
283     if (!LoggingOn(LF, LL))
284         return;
285     
286     Frame *pFrame = this;
287     while (pFrame != FRAME_TOP)
288     {
289         pFrame->LogFrame(LF, LL);
290         pFrame = pFrame->m_Next;
291     }
292 } // void Frame::LogFrameChain()
293
294 //-----------------------------------------------------------------------
295 #endif // _DEBUG_IMPL
296 //-----------------------------------------------------------------------
297
298 #ifndef DACCESS_COMPILE
299
300 // This hashtable contains the vtable value of every Frame type.
301 static PtrHashMap* s_pFrameVTables = NULL;
302
303 // static
304 void Frame::Init()
305 {
306     CONTRACTL
307     {
308         THROWS;
309         GC_NOTRIGGER;
310         MODE_ANY;
311     }
312     CONTRACTL_END;
313     // create a table big enough for all the frame types, not in asynchronous mode, and with no lock owner
314     s_pFrameVTables = ::new PtrHashMap;
315     s_pFrameVTables->Init(2 * FRAME_TYPES_COUNT, FALSE, &g_lockTrustMeIAmThreadSafe);
316 #define FRAME_TYPE_NAME(frameType)                          \
317     s_pFrameVTables->InsertValue(frameType::GetMethodFrameVPtr(), \
318                                (LPVOID) frameType::GetMethodFrameVPtr());
319 #include "frames.h"
320
321 } // void Frame::Init()
322
323 // static
324 void Frame::Term()
325 {
326     LIMITED_METHOD_CONTRACT;
327     delete s_pFrameVTables;
328     s_pFrameVTables = NULL;
329 }
330
331 #endif // DACCESS_COMPILE
332
333 // Returns true if the Frame's VTablePtr is valid
334
335 // static
336 bool Frame::HasValidVTablePtr(Frame * pFrame)
337 {
338     WRAPPER_NO_CONTRACT;
339
340     if (pFrame == NULL || pFrame == FRAME_TOP)
341         return false;
342     
343 #ifndef DACCESS_COMPILE
344     TADDR vptr = pFrame->GetVTablePtr();
345     //
346     // Helper MethodFrame,GCFrame,DebuggerSecurityCodeMarkFrame are the most 
347     // common frame types, explicitly check for them.
348     //
349     if (vptr == HelperMethodFrame::GetMethodFrameVPtr())
350         return true;
351
352     if (vptr == GCFrame::GetMethodFrameVPtr())
353         return true;
354
355     if (vptr == DebuggerSecurityCodeMarkFrame::GetMethodFrameVPtr())
356         return true;
357
358     //
359     // otherwise consult the hashtable
360     //
361     if (s_pFrameVTables->LookupValue(vptr, (LPVOID) vptr) == (LPVOID) INVALIDENTRY)
362         return false;
363 #endif
364
365     return true;
366 }
367
368 // Returns the location of the expected GSCookie,
369 // Return NULL if the frame's vtable pointer is corrupt
370 //
371 // Note that Frame::GetGSCookiePtr is a virtual method, 
372 // and so it cannot be used without first checking if
373 // the vtable is valid.
374
375 // static
376 PTR_GSCookie Frame::SafeGetGSCookiePtr(Frame * pFrame)
377 {
378     WRAPPER_NO_CONTRACT;
379
380     _ASSERTE(pFrame != FRAME_TOP);
381
382     if (Frame::HasValidVTablePtr(pFrame))
383         return pFrame->GetGSCookiePtr();
384     else
385         return NULL;
386 }
387
388 //-----------------------------------------------------------------------
389 #ifndef DACCESS_COMPILE
390 //-----------------------------------------------------------------------
391 // Link and Unlink this frame.
392 //-----------------------------------------------------------------------
393
394 VOID Frame::Push()
395 {
396     CONTRACTL
397     {
398         NOTHROW;
399         GC_NOTRIGGER;
400         MODE_COOPERATIVE;
401         SO_TOLERANT;
402     }
403     CONTRACTL_END;
404
405     Push(GetThread());
406 }
407
408 VOID Frame::Push(Thread *pThread)
409 {
410     CONTRACTL
411     {
412         NOTHROW;
413         GC_NOTRIGGER;
414         MODE_COOPERATIVE;
415         SO_TOLERANT;
416     }
417     CONTRACTL_END;
418
419     _ASSERTE(*GetGSCookiePtr() == GetProcessGSCookie());
420     
421     m_Next = pThread->GetFrame();
422
423     // PAGE_SIZE is used to relax the assert for cases where two Frames are
424     // declared in the same source function. We cannot predict the order
425     // in which the C compiler will lay them out in the stack frame.
426     // So PAGE_SIZE is a guess of the maximum stack frame size of any method
427     // with multiple Frames in mscorwks.dll
428     _ASSERTE(((m_Next == FRAME_TOP) ||
429               (PBYTE(m_Next) + (2 * PAGE_SIZE)) > PBYTE(this)) &&
430              "Pushing a frame out of order ?");
431     
432     _ASSERTE(// If AssertOnFailFast is set, the test expects to do stack overrun 
433              // corruptions. In that case, the Frame chain may be corrupted,
434              // and the rest of the assert is not valid.
435              // Note that the corrupted Frame chain will be detected 
436              // during stack-walking.
437              !g_pConfig->fAssertOnFailFast() ||
438              (m_Next == FRAME_TOP) ||
439              (*m_Next->GetGSCookiePtr() == GetProcessGSCookie()));
440     
441     pThread->SetFrame(this);
442 }
443
444 VOID Frame::Pop()
445 {
446     CONTRACTL
447     {
448         NOTHROW;
449         GC_NOTRIGGER;
450         MODE_COOPERATIVE;
451         SO_TOLERANT;
452     }
453     CONTRACTL_END;
454
455     Pop(GetThread());
456 }
457
458 VOID Frame::Pop(Thread *pThread)
459 {
460     CONTRACTL
461     {
462         NOTHROW;
463         GC_NOTRIGGER;
464         MODE_COOPERATIVE;
465         SO_TOLERANT;
466     }
467     CONTRACTL_END;
468
469     _ASSERTE(pThread->GetFrame() == this && "Popping a frame out of order ?");
470     _ASSERTE(*GetGSCookiePtr() == GetProcessGSCookie());
471     _ASSERTE(// If AssertOnFailFast is set, the test expects to do stack overrun 
472              // corruptions. In that case, the Frame chain may be corrupted,
473              // and the rest of the assert is not valid.
474              // Note that the corrupted Frame chain will be detected 
475              // during stack-walking.
476              !g_pConfig->fAssertOnFailFast() ||
477              (m_Next == FRAME_TOP) ||
478              (*m_Next->GetGSCookiePtr() == GetProcessGSCookie()));
479
480     pThread->SetFrame(m_Next);
481     m_Next = NULL;
482 }
483
484 #if defined(FEATURE_PAL) && !defined(DACCESS_COMPILE) && !defined(CROSSGEN_COMPILE)
485 void Frame::PopIfChained()
486 {      
487     CONTRACTL
488     {
489         NOTHROW;
490         GC_NOTRIGGER;
491         MODE_COOPERATIVE;
492         SO_TOLERANT;
493     }
494     CONTRACTL_END;
495
496     if (m_Next != NULL)
497     {
498         GCX_COOP();
499         // When the frame is destroyed, make sure it is no longer in the
500         // frame chain managed by the Thread.
501         Pop();
502     }
503 }      
504 #endif // FEATURE_PAL && !DACCESS_COMPILE && !CROSSGEN_COMPILE
505
506 //-----------------------------------------------------------------------
507 #endif // #ifndef DACCESS_COMPILE
508 //---------------------------------------------------------------
509 // Get the extra param for shared generic code.
510 //---------------------------------------------------------------
511 PTR_VOID TransitionFrame::GetParamTypeArg()
512 {
513     CONTRACTL
514     {
515         NOTHROW;
516         GC_NOTRIGGER;
517         MODE_ANY;
518         SUPPORTS_DAC;
519     }
520     CONTRACTL_END;
521
522     // This gets called while creating stack traces during exception handling.
523     // Using the ArgIterator constructor calls ArgIterator::Init which calls GetInitialOfsAdjust
524     // which calls SizeOfArgStack, which thinks it may load value types.
525     // However all these will have previously been loaded.
526     // 
527     // I'm not entirely convinced this is the best places to put this: CrawlFrame::GetExactGenericArgsToken
528     // may be another option.
529     ENABLE_FORBID_GC_LOADER_USE_IN_THIS_SCOPE();
530
531     MethodDesc *pFunction = GetFunction();
532     _ASSERTE (pFunction->RequiresInstArg());
533
534     MetaSig msig(pFunction);
535     ArgIterator argit (&msig);
536         
537     INT offs = argit.GetParamTypeArgOffset();
538
539     TADDR taParamTypeArg = *PTR_TADDR(GetTransitionBlock() + offs);
540     return PTR_VOID(taParamTypeArg);
541 }
542
543 TADDR TransitionFrame::GetAddrOfThis()
544 {
545     WRAPPER_NO_CONTRACT;
546     return GetTransitionBlock() + ArgIterator::GetThisOffset();
547 }
548
549 VASigCookie * TransitionFrame::GetVASigCookie()
550 {
551 #if defined(_TARGET_X86_)
552     LIMITED_METHOD_CONTRACT;
553     return dac_cast<PTR_VASigCookie>(
554         *dac_cast<PTR_TADDR>(GetTransitionBlock() +
555         sizeof(TransitionBlock)));
556 #else
557     WRAPPER_NO_CONTRACT;
558     MetaSig msig(GetFunction());
559     ArgIterator argit(&msig);
560     return PTR_VASigCookie(
561         *dac_cast<PTR_TADDR>(GetTransitionBlock() + argit.GetVASigCookieOffset()));
562 #endif
563 }
564
565 #ifndef DACCESS_COMPILE
566 PrestubMethodFrame::PrestubMethodFrame(TransitionBlock * pTransitionBlock, MethodDesc * pMD)
567     : FramedMethodFrame(pTransitionBlock, pMD)
568 {
569     LIMITED_METHOD_CONTRACT;
570 }
571 #endif // #ifndef DACCESS_COMPILE
572
573 BOOL PrestubMethodFrame::TraceFrame(Thread *thread, BOOL fromPatch,
574                                     TraceDestination *trace, REGDISPLAY *regs)
575 {
576     WRAPPER_NO_CONTRACT;
577
578     //
579     // We want to set a frame patch, unless we're already at the
580     // frame patch, in which case we'll trace stable entrypoint which 
581     // should be set by now.
582     //
583
584     if (fromPatch)
585     {
586         trace->InitForStub(GetFunction()->GetStableEntryPoint());
587     }
588     else
589     {
590         trace->InitForStub(GetPreStubEntryPoint());
591     }
592
593     LOG((LF_CORDB, LL_INFO10000,
594          "PrestubMethodFrame::TraceFrame: ip=" FMT_ADDR "\n", DBG_ADDR(trace->GetAddress()) ));
595     
596     return TRUE;
597 }
598
599 #ifndef DACCESS_COMPILE
600 //-----------------------------------------------------------------------
601 // A rather specialized routine for the exclusive use of StubDispatch.
602 //-----------------------------------------------------------------------
603 StubDispatchFrame::StubDispatchFrame(TransitionBlock * pTransitionBlock)
604     : FramedMethodFrame(pTransitionBlock, NULL)
605 {
606     LIMITED_METHOD_CONTRACT;
607
608     m_pRepresentativeMT = NULL;
609     m_representativeSlot = 0;
610
611     m_pZapModule = NULL;
612     m_pIndirection = NULL;
613
614     m_pGCRefMap = NULL;
615 }
616
617 #endif // #ifndef DACCESS_COMPILE
618
619 MethodDesc* StubDispatchFrame::GetFunction()
620 {
621     CONTRACTL {
622         NOTHROW;
623         GC_NOTRIGGER;
624         SO_TOLERANT;
625     } CONTRACTL_END;
626
627     MethodDesc * pMD = m_pMD;
628
629     if (m_pMD == NULL)
630     {
631         if (m_pRepresentativeMT != NULL)
632         {
633             pMD = m_pRepresentativeMT->GetMethodDescForSlot(m_representativeSlot);
634 #ifndef DACCESS_COMPILE
635             m_pMD = pMD;
636 #endif
637         }
638     }
639
640     return pMD;
641 }
642
643 static PTR_BYTE FindGCRefMap(PTR_Module pZapModule, TADDR ptr)
644 {
645     LIMITED_METHOD_DAC_CONTRACT;
646
647     PEImageLayout *pNativeImage = pZapModule->GetNativeOrReadyToRunImage();
648
649     RVA rva = pNativeImage->GetDataRva(ptr);
650
651     PTR_CORCOMPILE_IMPORT_SECTION pImportSection = pZapModule->GetImportSectionForRVA(rva);
652     if (pImportSection == NULL)
653         return NULL;
654
655     COUNT_T index = (rva - pImportSection->Section.VirtualAddress) / pImportSection->EntrySize;
656
657     PTR_BYTE pGCRefMap = dac_cast<PTR_BYTE>(pNativeImage->GetRvaData(pImportSection->AuxiliaryData));
658     _ASSERTE(pGCRefMap != NULL);
659
660     // GCRefMap starts with lookup index to limit size of linear scan that follows.
661     PTR_BYTE p = pGCRefMap + dac_cast<PTR_DWORD>(pGCRefMap)[index / GCREFMAP_LOOKUP_STRIDE];
662     COUNT_T remaining = index % GCREFMAP_LOOKUP_STRIDE;
663
664     while (remaining > 0)
665     {
666         while ((*p & 0x80) != 0)
667             p++;
668         p++;
669
670         remaining--;
671     }
672
673     return p;
674 }
675
676 PTR_BYTE StubDispatchFrame::GetGCRefMap()
677 {
678     CONTRACTL
679     {
680         NOTHROW;
681         GC_NOTRIGGER;
682     }
683     CONTRACTL_END;
684
685     PTR_BYTE pGCRefMap = m_pGCRefMap;
686
687     if (pGCRefMap == NULL)
688     {
689         if (m_pIndirection != NULL)
690         {
691             if (m_pZapModule == NULL)
692             {
693                 m_pZapModule = ExecutionManager::FindModuleForGCRefMap(m_pIndirection);
694             }
695
696             if (m_pZapModule != NULL)
697             {
698                 pGCRefMap = FindGCRefMap(m_pZapModule, m_pIndirection);
699             }
700
701 #ifndef DACCESS_COMPILE
702             if (pGCRefMap != NULL)
703             {
704                 m_pGCRefMap = pGCRefMap;
705             }
706             else
707             {
708                 // Clear the indirection to avoid retrying
709                 m_pIndirection = NULL;
710             }
711 #endif
712         }
713     }
714
715     return pGCRefMap;
716 }
717
718 void StubDispatchFrame::GcScanRoots(promote_func *fn, ScanContext* sc)
719 {
720     CONTRACTL
721     {
722         NOTHROW;
723         GC_NOTRIGGER;
724     }
725     CONTRACTL_END
726
727     FramedMethodFrame::GcScanRoots(fn, sc);
728
729     PTR_BYTE pGCRefMap = GetGCRefMap();
730     if (pGCRefMap != NULL)
731     { 
732         PromoteCallerStackUsingGCRefMap(fn, sc, pGCRefMap);
733     }
734     else
735     {
736         PromoteCallerStack(fn, sc);
737     }
738 }
739
740 BOOL StubDispatchFrame::TraceFrame(Thread *thread, BOOL fromPatch,
741                                     TraceDestination *trace, REGDISPLAY *regs)
742 {
743     WRAPPER_NO_CONTRACT;
744
745     //
746     // We want to set a frame patch, unless we're already at the
747     // frame patch, in which case we'll trace stable entrypoint which 
748     // should be set by now.
749     //
750
751     if (fromPatch)
752     {
753         trace->InitForStub(GetFunction()->GetStableEntryPoint());
754     }
755     else
756     {
757         trace->InitForStub(GetPreStubEntryPoint());
758     }
759
760     LOG((LF_CORDB, LL_INFO10000,
761          "StubDispatchFrame::TraceFrame: ip=" FMT_ADDR "\n", DBG_ADDR(trace->GetAddress()) ));
762     
763     return TRUE;
764 }
765
766 Frame::Interception StubDispatchFrame::GetInterception()
767 {
768     LIMITED_METHOD_CONTRACT;
769
770     return INTERCEPTION_NONE;
771 }
772
773 #ifndef DACCESS_COMPILE
774 ExternalMethodFrame::ExternalMethodFrame(TransitionBlock * pTransitionBlock)
775     : FramedMethodFrame(pTransitionBlock, NULL)
776 {
777     LIMITED_METHOD_CONTRACT;
778
779     m_pIndirection = NULL;
780     m_pZapModule = NULL;
781
782     m_pGCRefMap = NULL;
783 }
784 #endif // !DACCESS_COMPILE
785
786 void ExternalMethodFrame::GcScanRoots(promote_func *fn, ScanContext* sc)
787 {
788     CONTRACTL
789     {
790         NOTHROW;
791         GC_NOTRIGGER;
792     }
793     CONTRACTL_END
794
795     FramedMethodFrame::GcScanRoots(fn, sc);
796     PromoteCallerStackUsingGCRefMap(fn, sc, GetGCRefMap());
797 }
798
799 PTR_BYTE ExternalMethodFrame::GetGCRefMap()
800 {
801     LIMITED_METHOD_DAC_CONTRACT;
802
803     PTR_BYTE pGCRefMap = m_pGCRefMap;
804
805     if (pGCRefMap == NULL)
806     {
807         if (m_pIndirection != NULL)
808         {
809             pGCRefMap = FindGCRefMap(m_pZapModule, m_pIndirection);
810 #ifndef DACCESS_COMPILE
811             m_pGCRefMap = pGCRefMap;
812 #endif
813         }
814     }
815
816     _ASSERTE(pGCRefMap != NULL);
817     return pGCRefMap;
818 }
819
820 Frame::Interception ExternalMethodFrame::GetInterception()
821 {
822     LIMITED_METHOD_CONTRACT;
823
824     return INTERCEPTION_NONE;
825 }
826
827 Frame::Interception PrestubMethodFrame::GetInterception()
828 {
829     LIMITED_METHOD_DAC_CONTRACT;
830
831     //
832     // The only direct kind of interception done by the prestub 
833     // is class initialization.
834     //
835
836     return INTERCEPTION_PRESTUB;
837 }
838
839 #ifdef FEATURE_READYTORUN
840
841 #ifndef DACCESS_COMPILE
842 DynamicHelperFrame::DynamicHelperFrame(TransitionBlock * pTransitionBlock, int dynamicHelperFrameFlags)
843     : FramedMethodFrame(pTransitionBlock, NULL)
844 {
845     LIMITED_METHOD_CONTRACT;
846
847     m_dynamicHelperFrameFlags = dynamicHelperFrameFlags;
848 }
849 #endif // !DACCESS_COMPILE
850
851 void DynamicHelperFrame::GcScanRoots(promote_func *fn, ScanContext* sc)
852 {
853     CONTRACTL
854     {
855         NOTHROW;
856         GC_NOTRIGGER;
857     }
858     CONTRACTL_END
859
860     FramedMethodFrame::GcScanRoots(fn, sc);
861
862     PTR_PTR_Object pArgumentRegisters = dac_cast<PTR_PTR_Object>(GetTransitionBlock() + TransitionBlock::GetOffsetOfArgumentRegisters());
863
864     if (m_dynamicHelperFrameFlags & DynamicHelperFrameFlags_ObjectArg)
865     {
866         TADDR pArgument = GetTransitionBlock() + TransitionBlock::GetOffsetOfArgumentRegisters();
867 #ifdef _TARGET_X86_
868         // x86 is special as always
869         pArgument += offsetof(ArgumentRegisters, ECX);
870 #endif
871         (*fn)(dac_cast<PTR_PTR_Object>(pArgument), sc, CHECK_APP_DOMAIN);
872     }
873
874     if (m_dynamicHelperFrameFlags & DynamicHelperFrameFlags_ObjectArg2)
875     {
876         TADDR pArgument = GetTransitionBlock() + TransitionBlock::GetOffsetOfArgumentRegisters();
877 #ifdef _TARGET_X86_
878         // x86 is special as always
879         pArgument += offsetof(ArgumentRegisters, EDX);
880 #else
881         pArgument += sizeof(TADDR);
882 #endif
883         (*fn)(dac_cast<PTR_PTR_Object>(pArgument), sc, CHECK_APP_DOMAIN);
884     }
885 }
886
887 #endif // FEATURE_READYTORUN
888
889
890 #ifndef DACCESS_COMPILE
891
892 #ifdef FEATURE_COMINTEROP
893 //-----------------------------------------------------------------------
894 // A rather specialized routine for the exclusive use of the COM PreStub.
895 //-----------------------------------------------------------------------
896 VOID
897 ComPrestubMethodFrame::Init()
898 {
899     WRAPPER_NO_CONTRACT;
900
901     // Initializes the frame's VPTR. This assumes C++ puts the vptr
902     // at offset 0 for a class not using MI, but this is no different
903     // than the assumption that COM Classic makes.
904     *((TADDR*)this) = GetMethodFrameVPtr();
905     *GetGSCookiePtr() = GetProcessGSCookie();
906 }
907 #endif // FEATURE_COMINTEROP
908
909 //-----------------------------------------------------------------------
910 // GCFrames
911 //-----------------------------------------------------------------------
912
913
914 //--------------------------------------------------------------------
915 // This constructor pushes a new GCFrame on the frame chain.
916 //--------------------------------------------------------------------
917 GCFrame::GCFrame(OBJECTREF *pObjRefs, UINT numObjRefs, BOOL maybeInterior)
918 {
919     CONTRACTL
920     {
921         NOTHROW;
922         GC_NOTRIGGER;
923         MODE_COOPERATIVE;
924         SO_TOLERANT;
925     }
926     CONTRACTL_END;
927
928     Init(GetThread(), pObjRefs, numObjRefs, maybeInterior);
929 }
930
931 GCFrame::GCFrame(Thread *pThread, OBJECTREF *pObjRefs, UINT numObjRefs, BOOL maybeInterior)
932 {
933     CONTRACTL
934     {
935         NOTHROW;
936         GC_NOTRIGGER;
937         MODE_COOPERATIVE;
938         SO_TOLERANT;
939     }
940     CONTRACTL_END;
941
942     Init(pThread, pObjRefs, numObjRefs, maybeInterior);
943 }
944
945 void GCFrame::Init(Thread *pThread, OBJECTREF *pObjRefs, UINT numObjRefs, BOOL maybeInterior)
946 {
947     CONTRACTL
948     {
949         NOTHROW;
950         GC_NOTRIGGER;
951         MODE_COOPERATIVE;
952         SO_TOLERANT;
953     }
954     CONTRACTL_END;
955
956 #ifdef USE_CHECKED_OBJECTREFS
957     if (!maybeInterior) {
958         UINT i;
959         for(i = 0; i < numObjRefs; i++)
960             Thread::ObjectRefProtected(&pObjRefs[i]);
961         
962         for (i = 0; i < numObjRefs; i++) {
963             pObjRefs[i].Validate();
964         }
965     }
966
967 #if 0  // We'll want to restore this goodness check at some time. For now, the fact that we use
968        // this as temporary backstops in our loader exception conversions means we're highly
969        // exposed to infinite stack recursion should the loader be invoked during a stackwalk.
970        // So we'll do without.
971
972     if (g_pConfig->GetGCStressLevel() != 0 && IsProtectedByGCFrame(pObjRefs)) {
973         _ASSERTE(!"This objectref is already protected by a GCFrame. Protecting it twice will corrupt the GC.");
974     }
975 #endif
976
977 #endif
978
979     m_pObjRefs      = pObjRefs;
980     m_numObjRefs    = numObjRefs;
981     m_pCurThread    = pThread;
982     m_MaybeInterior = maybeInterior;
983
984     Frame::Push(m_pCurThread);
985 }
986
987
988 //
989 // GCFrame Object Scanning
990 //
991 // This handles scanning/promotion of GC objects that were
992 // protected by the programmer explicitly protecting it in a GC Frame
993 // via the GCPROTECTBEGIN / GCPROTECTEND facility...
994 //
995
996 #endif // !DACCESS_COMPILE
997
998 void GCFrame::GcScanRoots(promote_func *fn, ScanContext* sc)
999 {
1000     WRAPPER_NO_CONTRACT;
1001
1002     PTR_PTR_Object pRefs = dac_cast<PTR_PTR_Object>(m_pObjRefs);
1003
1004     for (UINT i = 0;i < m_numObjRefs; i++)  {
1005
1006         LOG((LF_GC, INFO3, "GC Protection Frame Promoting" FMT_ADDR "to",
1007              DBG_ADDR(OBJECTREF_TO_UNCHECKED_OBJECTREF(m_pObjRefs[i])) ));
1008         if (m_MaybeInterior)
1009             PromoteCarefully(fn, pRefs + i, sc, GC_CALL_INTERIOR|CHECK_APP_DOMAIN);
1010         else
1011             (*fn)(pRefs + i, sc, 0);
1012         LOG((LF_GC, INFO3, FMT_ADDR "\n", DBG_ADDR(OBJECTREF_TO_UNCHECKED_OBJECTREF(m_pObjRefs[i])) ));
1013     }
1014 }
1015
1016 #ifdef FEATURE_REMOTING
1017 #include "objectclone.h"
1018 void GCSafeCollectionFrame::GcScanRoots(promote_func *fn, ScanContext* sc)
1019 {
1020     WRAPPER_NO_CONTRACT;
1021     
1022     PTR_GCSafeCollection collection = dac_cast<PTR_GCSafeCollection>(m_pCollection);
1023     collection->ReportGCRefs(fn, sc);
1024 }
1025
1026 #ifndef DACCESS_COMPILE
1027 GCSafeCollectionFrame::GCSafeCollectionFrame(void *collection)
1028 {
1029     WRAPPER_NO_CONTRACT;
1030     
1031     _ASSERTE(collection != NULL);
1032     m_pCollection = collection;
1033
1034     Frame::Push();
1035 }
1036
1037 VOID GCSafeCollectionFrame::Pop()
1038 {
1039     LIMITED_METHOD_CONTRACT;
1040     Frame::Pop();
1041 }
1042 #endif // !DACCESS_COMPILE
1043 #endif // FEATURE_REMOTING
1044
1045 #ifndef DACCESS_COMPILE
1046 //--------------------------------------------------------------------
1047 // Pops the GCFrame and cancels the GC protection.
1048 //--------------------------------------------------------------------
1049 VOID GCFrame::Pop()
1050 {
1051     WRAPPER_NO_CONTRACT;
1052
1053     Frame::Pop(m_pCurThread);
1054 #ifdef _DEBUG
1055     m_pCurThread->EnableStressHeap();
1056     for(UINT i = 0; i < m_numObjRefs; i++)
1057         Thread::ObjectRefNew(&m_pObjRefs[i]);       // Unprotect them
1058 #endif
1059 }
1060
1061 #ifdef FEATURE_INTERPRETER
1062 // Methods of IntepreterFrame.
1063 InterpreterFrame::InterpreterFrame(Interpreter* interp) 
1064   : Frame(), m_interp(interp)
1065 {
1066     Push();
1067 }
1068
1069
1070 MethodDesc* InterpreterFrame::GetFunction()
1071 {
1072     return m_interp->GetMethodDesc();
1073 }
1074
1075 void InterpreterFrame::GcScanRoots(promote_func *fn, ScanContext* sc)
1076 {
1077     return m_interp->GCScanRoots(fn, sc);
1078 }
1079
1080 #endif // FEATURE_INTERPRETER
1081
1082 #if defined(_DEBUG) && !defined (DACCESS_COMPILE)
1083
1084 struct IsProtectedByGCFrameStruct
1085 {
1086     OBJECTREF       *ppObjectRef;
1087     UINT             count;
1088 };
1089
1090 static StackWalkAction IsProtectedByGCFrameStackWalkFramesCallback(
1091     CrawlFrame      *pCF,
1092     VOID            *pData
1093 )
1094 {
1095     DEBUG_ONLY_FUNCTION;
1096     WRAPPER_NO_CONTRACT;
1097
1098     IsProtectedByGCFrameStruct *pd = (IsProtectedByGCFrameStruct*)pData;
1099     Frame *pFrame = pCF->GetFrame();
1100     if (pFrame) {
1101         if (pFrame->Protects(pd->ppObjectRef)) {
1102             pd->count++;
1103         }
1104     }
1105     return SWA_CONTINUE;
1106 }
1107
1108 BOOL IsProtectedByGCFrame(OBJECTREF *ppObjectRef)
1109 {
1110     DEBUG_ONLY_FUNCTION;
1111     WRAPPER_NO_CONTRACT;
1112
1113     // Just report TRUE if GCStress is not on.  This satisfies the asserts that use this
1114     // code without the cost of actually determining it.
1115     if (!GCStress<cfg_any>::IsEnabled())
1116         return TRUE;
1117
1118     if (ppObjectRef == NULL) {
1119         return TRUE;
1120     }
1121
1122     CONTRACT_VIOLATION(ThrowsViolation);
1123     ENABLE_FORBID_GC_LOADER_USE_IN_THIS_SCOPE ();
1124     IsProtectedByGCFrameStruct d = {ppObjectRef, 0};
1125     GetThread()->StackWalkFrames(IsProtectedByGCFrameStackWalkFramesCallback, &d);
1126     if (d.count > 1) {
1127         _ASSERTE(!"Multiple GCFrames protecting the same pointer. This will cause GC corruption!");
1128     }
1129     return d.count != 0;
1130 }
1131 #endif // _DEBUG
1132
1133 #endif //!DACCESS_COMPILE
1134
1135 void ProtectByRefsFrame::GcScanRoots(promote_func *fn, ScanContext *sc)
1136 {
1137     CONTRACTL
1138     {
1139         NOTHROW;
1140         GC_NOTRIGGER;
1141     }
1142     CONTRACTL_END
1143
1144     ByRefInfo *pByRefInfos = m_brInfo;
1145     while (pByRefInfos)
1146     {
1147         if (!CorIsPrimitiveType(pByRefInfos->typ))
1148         {
1149             TADDR pData = PTR_HOST_MEMBER_TADDR(ByRefInfo, pByRefInfos, data);
1150
1151             if (pByRefInfos->typeHandle.IsValueType())
1152             {
1153                 ReportPointersFromValueType(fn, sc, pByRefInfos->typeHandle.GetMethodTable(), PTR_VOID(pData));
1154             }
1155             else
1156             {
1157                 PTR_PTR_Object ppObject = PTR_PTR_Object(pData);
1158
1159                 LOG((LF_GC, INFO3, "ProtectByRefs Frame Promoting" FMT_ADDR "to ", DBG_ADDR(*ppObject)));
1160
1161                 (*fn)(ppObject, sc, CHECK_APP_DOMAIN);
1162
1163                 LOG((LF_GC, INFO3, FMT_ADDR "\n", DBG_ADDR(*ppObject) ));
1164             }
1165         }
1166         pByRefInfos = pByRefInfos->pNext;
1167     }
1168 }
1169
1170 void ProtectValueClassFrame::GcScanRoots(promote_func *fn, ScanContext *sc)
1171 {
1172     CONTRACTL
1173     {
1174         NOTHROW;
1175         GC_NOTRIGGER;
1176     }
1177     CONTRACTL_END
1178
1179     ValueClassInfo *pVCInfo = m_pVCInfo;
1180     while (pVCInfo != NULL)
1181     {
1182         _ASSERTE(pVCInfo->pMT->IsValueType());
1183         ReportPointersFromValueType(fn, sc, pVCInfo->pMT, pVCInfo->pData);
1184         pVCInfo = pVCInfo->pNext;
1185     }
1186 }
1187
1188 //
1189 // Promote Caller Stack
1190 //
1191 //
1192
1193 void TransitionFrame::PromoteCallerStack(promote_func* fn, ScanContext* sc)
1194 {
1195     WRAPPER_NO_CONTRACT;
1196     
1197     // I believe this is the contract:
1198     //CONTRACTL
1199     //{
1200     //    INSTANCE_CHECK;
1201     //    NOTHROW;
1202     //    GC_NOTRIGGER;
1203     //    FORBID_FAULT;
1204     //    MODE_ANY;
1205     //}
1206     //CONTRACTL_END
1207     
1208     MethodDesc *pFunction;
1209     
1210     LOG((LF_GC, INFO3, "    Promoting method caller Arguments\n" ));
1211
1212     // We're going to have to look at the signature to determine
1213     // which arguments a are pointers....First we need the function
1214     pFunction = GetFunction();
1215     if (pFunction == NULL)
1216         return;
1217
1218     // Now get the signature...
1219     Signature callSignature = pFunction->GetSignature();
1220     if (callSignature.IsEmpty())
1221     {
1222         return;
1223     }
1224
1225     //If not "vararg" calling convention, assume "default" calling convention
1226     if (!MetaSig::IsVarArg(pFunction->GetModule(), callSignature))
1227     {
1228         MetaSig msig(pFunction);
1229         PromoteCallerStackHelper (fn, sc, pFunction, &msig);
1230     }
1231     else
1232     {
1233         VASigCookie *varArgSig = GetVASigCookie();
1234
1235         //Note: no instantiations needed for varargs
1236         MetaSig msig(varArgSig->signature,
1237                      varArgSig->pModule,
1238                      NULL);
1239         PromoteCallerStackHelper (fn, sc, pFunction, &msig);
1240     }
1241 }
1242
1243 void TransitionFrame::PromoteCallerStackHelper(promote_func* fn, ScanContext* sc,
1244                                                  MethodDesc *pFunction, MetaSig *pmsig)
1245 {
1246     WRAPPER_NO_CONTRACT;
1247     // I believe this is the contract:
1248     //CONTRACTL
1249     //{
1250     //    INSTANCE_CHECK;
1251     //    NOTHROW;
1252     //    GC_NOTRIGGER;
1253     //    FORBID_FAULT;
1254     //    MODE_ANY;
1255     //}
1256     //CONTRACTL_END
1257
1258     ArgIterator argit(pmsig);
1259
1260     TADDR pTransitionBlock = GetTransitionBlock();
1261
1262     // promote 'this' for non-static methods
1263     if (argit.HasThis() && pFunction != NULL)
1264     {
1265         BOOL interior = pFunction->GetMethodTable()->IsValueType() && !pFunction->IsUnboxingStub();
1266
1267         PTR_PTR_VOID pThis = dac_cast<PTR_PTR_VOID>(pTransitionBlock + argit.GetThisOffset());
1268         LOG((LF_GC, INFO3, 
1269              "    'this' Argument at " FMT_ADDR "promoted from" FMT_ADDR "\n", 
1270              DBG_ADDR(pThis), DBG_ADDR(*pThis) ));
1271
1272         if (interior)
1273             PromoteCarefully(fn, PTR_PTR_Object(pThis), sc, GC_CALL_INTERIOR|CHECK_APP_DOMAIN);
1274         else
1275             (fn)(PTR_PTR_Object(pThis), sc, CHECK_APP_DOMAIN);
1276     }
1277
1278     if (argit.HasRetBuffArg())
1279     {
1280         PTR_PTR_VOID pRetBuffArg = dac_cast<PTR_PTR_VOID>(pTransitionBlock + argit.GetRetBuffArgOffset());
1281         LOG((LF_GC, INFO3, "    ret buf Argument promoted from" FMT_ADDR "\n", DBG_ADDR(*pRetBuffArg) ));
1282         PromoteCarefully(fn, PTR_PTR_Object(pRetBuffArg), sc, GC_CALL_INTERIOR|CHECK_APP_DOMAIN);
1283     }
1284
1285     int argOffset;
1286     while ((argOffset = argit.GetNextOffset()) != TransitionBlock::InvalidOffset)
1287     {
1288         ArgDestination argDest(dac_cast<PTR_VOID>(pTransitionBlock), argOffset, argit.GetArgLocDescForStructInRegs());
1289         pmsig->GcScanRoots(&argDest, fn, sc);
1290     }
1291 }
1292
1293 #ifdef _TARGET_X86_
1294 UINT TransitionFrame::CbStackPopUsingGCRefMap(PTR_BYTE pGCRefMap)
1295 {
1296     LIMITED_METHOD_CONTRACT;
1297
1298     GCRefMapDecoder decoder(pGCRefMap);
1299     return decoder.ReadStackPop() * sizeof(TADDR);
1300 }
1301 #endif
1302
1303 void TransitionFrame::PromoteCallerStackUsingGCRefMap(promote_func* fn, ScanContext* sc, PTR_BYTE pGCRefMap)
1304 {
1305     WRAPPER_NO_CONTRACT;
1306
1307     GCRefMapDecoder decoder(pGCRefMap);
1308
1309 #ifdef _TARGET_X86_
1310     // Skip StackPop
1311     decoder.ReadStackPop();
1312 #endif
1313
1314     TADDR pTransitionBlock = GetTransitionBlock();
1315
1316     while (!decoder.AtEnd())
1317     {
1318         int pos = decoder.CurrentPos();
1319         int token = decoder.ReadToken();
1320
1321         int ofs;
1322
1323 #ifdef _TARGET_X86_
1324         ofs = (pos < NUM_ARGUMENT_REGISTERS) ?
1325             (TransitionBlock::GetOffsetOfArgumentRegisters() + ARGUMENTREGISTERS_SIZE - (pos + 1) * sizeof(TADDR)) :
1326             (TransitionBlock::GetOffsetOfArgs() + (pos - NUM_ARGUMENT_REGISTERS) * sizeof(TADDR));
1327 #else
1328         ofs = TransitionBlock::GetOffsetOfArgumentRegisters() + pos * sizeof(TADDR);
1329 #endif
1330
1331         PTR_TADDR ppObj = dac_cast<PTR_TADDR>(pTransitionBlock + ofs);
1332
1333         switch (token)
1334         {
1335         case GCREFMAP_SKIP:
1336             break;
1337         case GCREFMAP_REF:
1338             fn(dac_cast<PTR_PTR_Object>(ppObj), sc, CHECK_APP_DOMAIN);
1339             break;
1340         case GCREFMAP_INTERIOR:
1341             PromoteCarefully(fn, dac_cast<PTR_PTR_Object>(ppObj), sc, GC_CALL_INTERIOR | GC_CALL_CHECK_APP_DOMAIN);
1342             break;
1343         case GCREFMAP_METHOD_PARAM:
1344             if (sc->promotion)
1345             {
1346 #ifndef DACCESS_COMPILE
1347                 MethodDesc *pMDReal = dac_cast<PTR_MethodDesc>(*ppObj);
1348                 if (pMDReal != NULL)
1349                     GcReportLoaderAllocator(fn, sc, pMDReal->GetLoaderAllocator());
1350 #endif
1351             }
1352             break;
1353         case GCREFMAP_TYPE_PARAM:
1354             if (sc->promotion)
1355             {
1356 #ifndef DACCESS_COMPILE
1357                 MethodTable *pMTReal = dac_cast<PTR_MethodTable>(*ppObj);
1358                 if (pMTReal != NULL)
1359                     GcReportLoaderAllocator(fn, sc, pMTReal->GetLoaderAllocator());
1360 #endif
1361             }
1362             break;
1363         case GCREFMAP_VASIG_COOKIE:
1364             {
1365                 VASigCookie *varArgSig = dac_cast<PTR_VASigCookie>(*ppObj);
1366
1367                 //Note: no instantiations needed for varargs
1368                 MetaSig msig(varArgSig->signature,
1369                                 varArgSig->pModule,
1370                                 NULL);
1371                 PromoteCallerStackHelper (fn, sc, NULL, &msig);
1372             }
1373             break;
1374         default:
1375             _ASSERTE(!"Unknown GCREFMAP token");
1376             break;
1377         }
1378     }
1379 }
1380
1381 void PInvokeCalliFrame::PromoteCallerStack(promote_func* fn, ScanContext* sc)
1382 {
1383     WRAPPER_NO_CONTRACT;
1384
1385     LOG((LF_GC, INFO3, "    Promoting CALLI caller Arguments\n" ));
1386
1387     // get the signature
1388     VASigCookie *varArgSig = GetVASigCookie();
1389     if (varArgSig->signature.IsEmpty())
1390     {
1391         return;
1392     }
1393
1394     // no instantiations needed for varargs 
1395     MetaSig msig(varArgSig->signature,
1396                  varArgSig->pModule, 
1397                  NULL);
1398     PromoteCallerStackHelper(fn, sc, NULL, &msig);
1399 }
1400
1401 #ifndef DACCESS_COMPILE
1402 PInvokeCalliFrame::PInvokeCalliFrame(TransitionBlock * pTransitionBlock, VASigCookie * pVASigCookie, PCODE pUnmanagedTarget)
1403     : FramedMethodFrame(pTransitionBlock, NULL)
1404 {
1405     LIMITED_METHOD_CONTRACT;
1406
1407     m_pVASigCookie = pVASigCookie;
1408     m_pUnmanagedTarget = pUnmanagedTarget;
1409 }
1410 #endif // #ifndef DACCESS_COMPILE
1411
1412 #ifdef FEATURE_COMINTEROP
1413
1414 #ifndef DACCESS_COMPILE
1415 ComPlusMethodFrame::ComPlusMethodFrame(TransitionBlock * pTransitionBlock, MethodDesc * pMD)
1416     : FramedMethodFrame(pTransitionBlock, pMD)
1417 {
1418     LIMITED_METHOD_CONTRACT;
1419 }
1420 #endif // #ifndef DACCESS_COMPILE
1421
1422 //virtual
1423 void ComPlusMethodFrame::GcScanRoots(promote_func *fn, ScanContext* sc)
1424 {
1425     WRAPPER_NO_CONTRACT;
1426
1427     // ComPlusMethodFrame is only used in the event call / late bound call code path where we do not have IL stub
1428     // so we need to promote the arguments and return value manually.
1429
1430     FramedMethodFrame::GcScanRoots(fn, sc);
1431     PromoteCallerStack(fn, sc);
1432
1433     MetaSig::RETURNTYPE returnType = GetFunction()->ReturnsObject();
1434
1435     // Promote the returned object
1436     if(returnType == MetaSig::RETOBJ)
1437         (*fn)(GetReturnObjectPtr(), sc, CHECK_APP_DOMAIN);
1438     else if (returnType == MetaSig::RETBYREF)
1439         PromoteCarefully(fn, GetReturnObjectPtr(), sc, GC_CALL_INTERIOR|CHECK_APP_DOMAIN);
1440 }
1441 #endif // FEATURE_COMINTEROP
1442
1443 #if defined (_DEBUG) && !defined (DACCESS_COMPILE)
1444 // For IsProtectedByGCFrame, we need to know whether a given object ref is protected 
1445 // by a ComPlusMethodFrame or a ComMethodFrame. Since GCScanRoots for those frames are 
1446 // quite complicated, we don't want to duplicate their logic so we call GCScanRoots with 
1447 // IsObjRefProtected (a fake promote function) and an extended ScanContext to do the checking.
1448
1449 struct IsObjRefProtectedScanContext : public ScanContext
1450 {
1451     OBJECTREF * oref_to_check;
1452     BOOL        oref_protected;
1453     IsObjRefProtectedScanContext (OBJECTREF * oref)
1454     {
1455         thread_under_crawl = GetThread ();
1456         promotion = TRUE;
1457         oref_to_check = oref;
1458         oref_protected = FALSE;
1459     }
1460 };
1461
1462 void IsObjRefProtected (Object** ppObj, ScanContext* sc, uint32_t)
1463 {
1464     LIMITED_METHOD_CONTRACT;
1465     IsObjRefProtectedScanContext * orefProtectedSc = (IsObjRefProtectedScanContext *)sc;
1466     if (ppObj == (Object **)(orefProtectedSc->oref_to_check))
1467         orefProtectedSc->oref_protected = TRUE;
1468 }
1469
1470 BOOL TransitionFrame::Protects(OBJECTREF * ppORef)
1471 {
1472     WRAPPER_NO_CONTRACT;
1473     IsObjRefProtectedScanContext sc (ppORef);
1474     // Set the stack limit for the scan to the SP of the managed frame above the transition frame
1475     sc.stack_limit = GetSP();
1476     GcScanRoots (IsObjRefProtected, &sc);
1477     return sc.oref_protected;
1478 }
1479 #endif //defined (_DEBUG) && !defined (DACCESS_COMPILE)
1480
1481 //+----------------------------------------------------------------------------
1482 //
1483 //  Method:     TPMethodFrame::GcScanRoots    public
1484 //
1485 //  Synopsis:   GC protects arguments on the stack
1486 //
1487
1488 //
1489 //+----------------------------------------------------------------------------
1490 #ifdef FEATURE_REMOTING
1491
1492 #ifndef DACCESS_COMPILE
1493 TPMethodFrame::TPMethodFrame(TransitionBlock * pTransitionBlock)
1494     : FramedMethodFrame(pTransitionBlock, NULL)
1495 {
1496     LIMITED_METHOD_CONTRACT;
1497 }
1498 #endif // #ifndef DACCESS_COMPILE
1499
1500 void TPMethodFrame::GcScanRoots(promote_func *fn, ScanContext* sc)
1501 {
1502     WRAPPER_NO_CONTRACT;
1503
1504     // Delegate to FramedMethodFrame
1505     FramedMethodFrame::GcScanRoots(fn, sc);
1506     FramedMethodFrame::PromoteCallerStack(fn, sc);
1507
1508     MetaSig::RETURNTYPE returnType = GetFunction()->ReturnsObject();
1509
1510     // Promote the returned object
1511     if(returnType == MetaSig::RETOBJ)
1512     {
1513         (*fn)(GetReturnObjectPtr(), sc, CHECK_APP_DOMAIN);
1514     }
1515     else if (returnType == MetaSig::RETBYREF)
1516     {
1517         PromoteCarefully(fn, GetReturnObjectPtr(), sc, GC_CALL_INTERIOR|CHECK_APP_DOMAIN);
1518     }
1519
1520     return;
1521 }
1522
1523 //+----------------------------------------------------------------------------
1524 //
1525 //  Method:     TPMethodFrame::TraceFrame    public
1526 //
1527 //  Synopsis:   Return where the frame will execute next - the result is filled
1528 //              into the given "trace" structure.  The frame is responsible for
1529 //              detecting where it is in its execution lifetime.
1530 //
1531 //
1532
1533 //
1534 //+----------------------------------------------------------------------------
1535 BOOL TPMethodFrame::TraceFrame(Thread *thread, BOOL fromPatch, 
1536                                TraceDestination *trace, REGDISPLAY *regs)
1537 {
1538     WRAPPER_NO_CONTRACT;
1539
1540     // We want to set a frame patch, unless we're already at the
1541     // frame patch, in which case we'll trace stable entrypoint which 
1542     // should be set by now.
1543
1544     if (fromPatch)
1545     {
1546         trace->InitForStub(GetFunction()->GetStableEntryPoint());
1547     }
1548     else
1549     {
1550 #ifdef DACCESS_COMPILE
1551         DacNotImpl();
1552 #else
1553         trace->InitForStub(GetEEFuncEntryPoint(TransparentProxyStubPatchLabel));
1554 #endif
1555     }
1556     return TRUE;
1557
1558 }
1559 #endif // FEATURE_REMOTING
1560
1561 #ifdef FEATURE_COMINTEROP
1562
1563 #ifdef _TARGET_X86_
1564 // Return the # of stack bytes pushed by the unmanaged caller.
1565 UINT ComMethodFrame::GetNumCallerStackBytes()
1566 {
1567     WRAPPER_NO_CONTRACT;
1568     SUPPORTS_DAC;
1569
1570     ComCallMethodDesc* pCMD = PTR_ComCallMethodDesc((TADDR)GetDatum());
1571     PREFIX_ASSUME(pCMD != NULL);
1572     // assumes __stdcall
1573     // compute the callee pop stack bytes
1574     return pCMD->GetNumStackBytes();
1575 }
1576 #endif // _TARGET_X86_
1577
1578 #ifndef DACCESS_COMPILE
1579 void ComMethodFrame::DoSecondPassHandlerCleanup(Frame * pCurFrame)
1580 {
1581     LIMITED_METHOD_CONTRACT;
1582
1583     // Find ComMethodFrame, noting any ContextTransitionFrame along the way
1584
1585     while ((pCurFrame != FRAME_TOP) && 
1586            (pCurFrame->GetVTablePtr() != ComMethodFrame::GetMethodFrameVPtr()))
1587     {
1588         if (pCurFrame->GetVTablePtr() == ContextTransitionFrame::GetMethodFrameVPtr())
1589         {
1590             // If there is a context transition before we find a ComMethodFrame, do nothing.  Expect that 
1591             // the AD transition code will perform the corresponding work after it pops its context 
1592             // transition frame and before it rethrows the exception.
1593             return;
1594         }
1595         pCurFrame = pCurFrame->PtrNextFrame();
1596     }
1597
1598     if (pCurFrame == FRAME_TOP)
1599         return;
1600
1601     ComMethodFrame * pComMethodFrame = (ComMethodFrame *)pCurFrame;
1602
1603     _ASSERTE(pComMethodFrame != NULL);
1604     Thread * pThread = GetThread();
1605     GCX_COOP_THREAD_EXISTS(pThread);
1606     // Unwind the frames till the entry frame (which was ComMethodFrame)
1607     pCurFrame = pThread->GetFrame();
1608     while ((pCurFrame != NULL) && (pCurFrame <= pComMethodFrame))
1609     {
1610         pCurFrame->ExceptionUnwind();
1611         pCurFrame = pCurFrame->PtrNextFrame();
1612     }
1613
1614     // At this point, pCurFrame would be the ComMethodFrame's predecessor frame
1615     // that we need to reset to.
1616     _ASSERTE((pCurFrame != NULL) && (pComMethodFrame->PtrNextFrame() == pCurFrame));
1617     pThread->SetFrame(pCurFrame);
1618 }
1619 #endif // !DACCESS_COMPILE
1620
1621 #endif // FEATURE_COMINTEROP
1622
1623
1624 #ifdef _TARGET_X86_
1625
1626 PTR_UMEntryThunk UMThkCallFrame::GetUMEntryThunk()
1627 {
1628     LIMITED_METHOD_DAC_CONTRACT;
1629     return dac_cast<PTR_UMEntryThunk>(GetDatum());
1630 }
1631
1632 #ifdef DACCESS_COMPILE
1633 void UMThkCallFrame::EnumMemoryRegions(CLRDataEnumMemoryFlags flags)
1634 {
1635     WRAPPER_NO_CONTRACT;
1636     UnmanagedToManagedFrame::EnumMemoryRegions(flags);
1637
1638     // Pieces of the UMEntryThunk need to be saved.
1639     UMEntryThunk *pThunk = GetUMEntryThunk();
1640     DacEnumMemoryRegion(dac_cast<TADDR>(pThunk), sizeof(UMEntryThunk));        
1641     
1642     UMThunkMarshInfo *pMarshInfo = pThunk->GetUMThunkMarshInfo();
1643     DacEnumMemoryRegion(dac_cast<TADDR>(pMarshInfo), sizeof(UMThunkMarshInfo));        
1644 }
1645 #endif
1646
1647 #endif // _TARGET_X86_
1648
1649 #ifndef DACCESS_COMPILE
1650
1651 #if defined(_MSC_VER) && defined(_TARGET_X86_)
1652 #pragma optimize("y", on)   // Small critical routines, don't put in EBP frame 
1653 #endif
1654
1655 // Initialization of HelperMethodFrame.
1656 void HelperMethodFrame::Push()
1657 {
1658     CONTRACTL {
1659         if (m_Attribs & FRAME_ATTR_NO_THREAD_ABORT) NOTHROW; else THROWS;
1660         GC_TRIGGERS;
1661         MODE_COOPERATIVE;
1662         SO_TOLERANT;
1663     } CONTRACTL_END;
1664
1665     //
1666     // Finish initialization
1667     //
1668
1669     // Compiler would not inline GetGSCookiePtr() because of it is virtual method.
1670     // Inline it manually and verify that it gives same result.
1671     _ASSERTE(GetGSCookiePtr() == (((GSCookie *)(this)) - 1));
1672     *(((GSCookie *)(this)) - 1) = GetProcessGSCookie();
1673
1674     _ASSERTE(!m_MachState.isValid());
1675
1676     Thread * pThread = ::GetThread();
1677     m_pThread = pThread;
1678
1679     // Push the frame
1680     Frame::Push(pThread);
1681
1682     if (!pThread->HasThreadStateOpportunistic((Thread::ThreadState)(Thread::TS_YieldRequested | Thread::TS_AbortRequested)))
1683         return;
1684
1685     // Outline the slow path for better perf
1686     PushSlowHelper();
1687 }
1688
1689 void HelperMethodFrame::Pop()
1690 {
1691     CONTRACTL {
1692         if (m_Attribs & FRAME_ATTR_NO_THREAD_ABORT) NOTHROW; else THROWS;
1693         GC_TRIGGERS;
1694         MODE_COOPERATIVE;
1695         SO_TOLERANT;
1696     } CONTRACTL_END;
1697
1698     Thread * pThread = m_pThread;
1699     
1700     if ((m_Attribs & FRAME_ATTR_NO_THREAD_ABORT) || !pThread->HasThreadStateOpportunistic(Thread::TS_AbortInitiated))
1701     {
1702         Frame::Pop(pThread);
1703         return;
1704     }
1705
1706     // Outline the slow path for better perf
1707     PopSlowHelper();
1708 }
1709
1710 #if defined(_MSC_VER) && defined(_TARGET_X86_)
1711 #pragma optimize("", on)     // Go back to command line default optimizations
1712 #endif
1713
1714 NOINLINE void HelperMethodFrame::PushSlowHelper()
1715 {
1716     CONTRACTL {
1717         if (m_Attribs & FRAME_ATTR_NO_THREAD_ABORT) NOTHROW; else THROWS;
1718         GC_TRIGGERS;
1719         MODE_COOPERATIVE;
1720         SO_TOLERANT;
1721     } CONTRACTL_END;
1722
1723     if (!(m_Attribs & FRAME_ATTR_NO_THREAD_ABORT))
1724     {
1725         if (m_pThread->IsAbortRequested())
1726         {
1727             m_pThread->HandleThreadAbort();
1728         }
1729
1730     }
1731
1732     if (m_pThread->IsYieldRequested())
1733     {
1734         __SwitchToThread(0, CALLER_LIMITS_SPINNING);
1735     }
1736 }
1737
1738 NOINLINE void HelperMethodFrame::PopSlowHelper()
1739 {
1740     CONTRACTL {
1741         THROWS;
1742         GC_TRIGGERS;
1743         MODE_COOPERATIVE;
1744         SO_TOLERANT;
1745     } CONTRACTL_END;
1746
1747     m_pThread->HandleThreadAbort();
1748     Frame::Pop(m_pThread);
1749 }
1750
1751 #endif // #ifndef DACCESS_COMPILE
1752
1753 MethodDesc* HelperMethodFrame::GetFunction()
1754 {
1755     WRAPPER_NO_CONTRACT;
1756
1757 #ifndef DACCESS_COMPILE
1758     InsureInit(false, NULL);
1759     return m_pMD;
1760 #else
1761     if (m_MachState.isValid())
1762     {
1763         return m_pMD;
1764     }
1765     else
1766     {
1767         return ECall::MapTargetBackToMethod(m_FCallEntry);
1768     }
1769 #endif
1770 }
1771
1772 //---------------------------------------------------------------------------------------
1773 //
1774 // Ensures the HelperMethodFrame gets initialized, if not already.
1775 //
1776 // Arguments:
1777 //      * initialInit -
1778 //         * true: ensure the simple, first stage of initialization has been completed.
1779 //             This is used when the HelperMethodFrame is first created.
1780 //         * false: complete any initialization that was left to do, if any.
1781 //      * unwindState - [out] DAC builds use this to return the unwound machine state.
1782 //      * hostCallPreference - (See code:HelperMethodFrame::HostCallPreference.)
1783 //
1784 // Return Value:
1785 //     Normally, the function always returns TRUE meaning the initialization succeeded.
1786 //     
1787 //     However, if hostCallPreference is NoHostCalls, AND if a callee (like
1788 //     LazyMachState::unwindLazyState) needed to acquire a JIT reader lock and was unable
1789 //     to do so (lest it re-enter the host), then InsureInit will abort and return FALSE.
1790 //     So any callers that specify hostCallPreference = NoHostCalls (which is not the
1791 //     default), should check for FALSE return, and refuse to use the HMF in that case.
1792 //     Currently only asynchronous calls made by profilers use that code path.
1793 //
1794
1795 BOOL HelperMethodFrame::InsureInit(bool initialInit,
1796                                     MachState * unwindState,
1797                                     HostCallPreference hostCallPreference /* = AllowHostCalls */) 
1798 {
1799     CONTRACTL {
1800         NOTHROW;
1801         GC_NOTRIGGER;
1802         SO_TOLERANT;
1803         if ((hostCallPreference == AllowHostCalls) && !m_MachState.isValid()) { HOST_CALLS; } else { HOST_NOCALLS; }
1804         SUPPORTS_DAC;
1805     } CONTRACTL_END;
1806
1807     if (m_MachState.isValid())
1808     {
1809         return TRUE;
1810     }
1811
1812     _ASSERTE(m_Attribs != 0xCCCCCCCC);
1813
1814 #ifndef DACCESS_COMPILE
1815     if (!initialInit)
1816     {
1817         m_pMD = ECall::MapTargetBackToMethod(m_FCallEntry);
1818
1819         // if this is an FCall, we should find it
1820         _ASSERTE(m_FCallEntry == 0 || m_pMD != 0);
1821     }
1822 #endif
1823
1824     // Because TRUE FCalls can be called from via reflection, com-interop, etc.,
1825     // we can't rely on the fact that we are called from jitted code to find the
1826     // caller of the FCALL.   Thus FCalls must erect the frame directly in the
1827     // FCall.  For JIT helpers, however, we can rely on this, and so they can
1828     // be sneakier and defer the HelperMethodFrame setup to a called worker method.
1829    
1830     // Work with a copy so that we only write the values once.
1831     // this avoids race conditions.
1832     LazyMachState* lazy = &m_MachState;
1833     DWORD threadId = m_pThread->GetOSThreadId();
1834     MachState unwound;
1835     
1836     if (!initialInit &&
1837         m_FCallEntry == 0 &&
1838         !(m_Attribs & Frame::FRAME_ATTR_EXACT_DEPTH)) // Jit Helper
1839     {
1840         LazyMachState::unwindLazyState(
1841             lazy, 
1842             &unwound, 
1843             threadId,
1844             0,
1845             hostCallPreference);
1846
1847 #if !defined(DACCESS_COMPILE)
1848         if (!unwound.isValid())
1849         {
1850             // This only happens if LazyMachState::unwindLazyState had to abort as a
1851             // result of failing to take a reader lock (because we told it not to yield,
1852             // but the writer lock was already held).  Since we've not yet updated
1853             // m_MachState, this HelperMethodFrame will still be considered not fully
1854             // initialized (so a future call into InsureInit() will attempt to complete
1855             // initialization again).
1856             // 
1857             // Note that, in DAC builds, the contract with LazyMachState::unwindLazyState
1858             // is a bit different, and it's expected that LazyMachState::unwindLazyState
1859             // will commonly return an unwound state with _pRetAddr==NULL (which counts
1860             // as an "invalid" MachState). So have DAC builds deliberately fall through
1861             // rather than aborting when unwound is invalid.
1862             _ASSERTE(hostCallPreference == NoHostCalls);
1863             return FALSE;
1864         }
1865 #endif // !defined(DACCESS_COMPILE)
1866     }
1867     else if (!initialInit &&
1868              (m_Attribs & Frame::FRAME_ATTR_CAPTURE_DEPTH_2) != 0)
1869     {
1870         // explictly told depth
1871         LazyMachState::unwindLazyState(lazy, &unwound, threadId, 2);
1872     }
1873     else
1874     {
1875         // True FCall 
1876         LazyMachState::unwindLazyState(lazy, &unwound, threadId, 1);
1877     }
1878
1879     _ASSERTE(unwound.isValid());
1880
1881 #if !defined(DACCESS_COMPILE)
1882     lazy->setLazyStateFromUnwind(&unwound);
1883 #else  // DACCESS_COMPILE
1884     if (unwindState)
1885     {
1886         *unwindState = unwound;
1887     }
1888 #endif // DACCESS_COMPILE
1889
1890     return TRUE;
1891 }
1892
1893
1894 #include "comdelegate.h"
1895
1896 Assembly* SecureDelegateFrame::GetAssembly()
1897 {
1898     WRAPPER_NO_CONTRACT;
1899
1900 #if !defined(DACCESS_COMPILE)
1901     // obtain the frame off the delegate pointer
1902     DELEGATEREF delegate = (DELEGATEREF) GetThis();
1903     _ASSERTE(delegate);
1904     if (!delegate->IsWrapperDelegate())
1905     {
1906         MethodDesc* pMethod = (MethodDesc*) delegate->GetMethodPtrAux();
1907         Assembly* pAssembly = pMethod->GetAssembly();
1908         _ASSERTE(pAssembly != NULL);
1909         return pAssembly;        
1910     }
1911     else
1912         return NULL;
1913 #else
1914     DacNotImpl();
1915     return NULL;
1916 #endif
1917 }
1918
1919 BOOL SecureDelegateFrame::TraceFrame(Thread *thread, BOOL fromPatch, TraceDestination *trace, REGDISPLAY *regs)
1920 {
1921     WRAPPER_NO_CONTRACT;
1922
1923     _ASSERTE(!fromPatch);
1924
1925     // Unlike multicast delegates, secure delegates only call one method.  So, we should just return false here
1926     // and let the step out logic continue to the caller of the secure delegate stub.
1927     LOG((LF_CORDB, LL_INFO1000, "SDF::TF: return FALSE\n"));
1928
1929     return FALSE;
1930 }
1931
1932 BOOL MulticastFrame::TraceFrame(Thread *thread, BOOL fromPatch,
1933                                 TraceDestination *trace, REGDISPLAY *regs)
1934 {
1935     CONTRACTL
1936     {
1937         THROWS;
1938         GC_NOTRIGGER;
1939         MODE_COOPERATIVE;
1940     }
1941     CONTRACTL_END;
1942
1943     _ASSERTE(!fromPatch);
1944
1945 #ifdef DACCESS_COMPILE
1946     return FALSE;
1947
1948 #else // !DACCESS_COMPILE
1949     LOG((LF_CORDB,LL_INFO10000, "MulticastFrame::TF FromPatch:0x%x, at 0x%x\n", fromPatch, GetControlPC(regs)));
1950
1951     // At this point we have no way to recover the Stub object from the control pc.  We can't use the MD stored
1952     // in the MulticastFrame because it points to the dummy Invoke() method, not the method we want to call.
1953
1954     BYTE *pbDel = NULL;
1955     int delegateCount = 0;
1956
1957 #if defined(_TARGET_X86_)
1958     // At this point the counter hasn't been incremented yet.
1959     delegateCount = *regs->pEdi + 1;
1960     pbDel = *(BYTE **)( (size_t)*(regs->pEsi) + GetOffsetOfTransitionBlock() + ArgIterator::GetThisOffset());
1961 #elif defined(_TARGET_AMD64_)
1962     // At this point the counter hasn't been incremented yet.
1963     delegateCount = (int)regs->pCurrentContext->Rdi + 1;
1964     pbDel = *(BYTE **)( (size_t)(regs->pCurrentContext->Rsi) + GetOffsetOfTransitionBlock() + ArgIterator::GetThisOffset());
1965 #elif defined(_TARGET_ARM_)
1966     // At this point the counter has not yet been incremented. Counter is in R7, frame pointer in R4.
1967     delegateCount = regs->pCurrentContext->R7 + 1;
1968     pbDel = *(BYTE **)( (size_t)(regs->pCurrentContext->R4) + GetOffsetOfTransitionBlock() + ArgIterator::GetThisOffset());
1969 #else
1970     delegateCount = 0;
1971     PORTABILITY_ASSERT("MulticastFrame::TraceFrame (frames.cpp)");
1972 #endif
1973
1974     int totalDelegateCount = (int)*(size_t*)(pbDel + DelegateObject::GetOffsetOfInvocationCount());
1975
1976     _ASSERTE( COMDelegate::IsTrueMulticastDelegate( ObjectToOBJECTREF((Object*)pbDel) ) );
1977
1978     if (delegateCount == totalDelegateCount)
1979     {
1980         LOG((LF_CORDB, LL_INFO1000, "MF::TF: Executed all stubs, should return\n"));
1981         // We've executed all the stubs, so we should return
1982         return FALSE;
1983     }
1984     else
1985     {
1986         // We're going to execute stub delegateCount next, so go and grab it.
1987         BYTE *pbDelInvocationList = *(BYTE **)(pbDel + DelegateObject::GetOffsetOfInvocationList());
1988
1989         pbDel = *(BYTE**)( ((ArrayBase *)pbDelInvocationList)->GetDataPtr() +
1990                            ((ArrayBase *)pbDelInvocationList)->GetComponentSize()*delegateCount);
1991
1992         _ASSERTE(pbDel);
1993         return DelegateInvokeStubManager::TraceDelegateObject(pbDel, trace);
1994     }
1995 #endif // !DACCESS_COMPILE
1996 }
1997
1998 #ifndef DACCESS_COMPILE
1999
2000 VOID InlinedCallFrame::Init()
2001 {
2002     WRAPPER_NO_CONTRACT;
2003
2004     *((TADDR *)this) = GetMethodFrameVPtr();
2005     
2006     // GetGSCookiePtr contains a virtual call and this is a perf critical method so we don't want to call it in ret builds
2007     GSCookie *ptrGS = (GSCookie *)((BYTE *)this - sizeof(GSCookie));
2008     _ASSERTE(ptrGS == GetGSCookiePtr());
2009
2010     *ptrGS = GetProcessGSCookie();
2011
2012     m_Datum = NULL;
2013     m_pCallSiteSP = NULL;
2014     m_pCallerReturnAddress = NULL;
2015 }
2016
2017 #if defined(_WIN64) && !defined(FEATURE_PAL)
2018
2019 EXTERN_C void PInvokeStubForHostInner(DWORD dwStackSize, LPVOID pStackFrame, LPVOID pTarget);
2020
2021 // C++ piece of one static stub for host on 64-bit. This is called by PInvokeStubForHost (PInvokeStubs.asm).
2022 void __stdcall PInvokeStubForHostWorker(DWORD dwStackSize, LPVOID pStackFrame, LPVOID pThis)
2023 {
2024     CONTRACTL
2025     {
2026         THROWS;
2027         GC_TRIGGERS;
2028         ENTRY_POINT;
2029     }
2030     CONTRACTL_END;
2031
2032     InlinedCallFrame *pFrame = (InlinedCallFrame *)GetThread()->GetFrame();
2033     _ASSERTE(InlinedCallFrame::FrameHasActiveCall(pFrame));
2034
2035     LPVOID pTarget = NULL;
2036     MethodDesc *pMD = pFrame->GetFunction();
2037
2038     if (pMD == NULL)
2039     {
2040         // This is a CALLI and m_Datum is a mangled target
2041         pTarget = (LPVOID)((UINT_PTR)pFrame->m_Datum >> 1);
2042     }
2043     else if (pMD->IsNDirect())
2044     {
2045         pTarget = ((NDirectMethodDesc *)pMD)->ndirect.m_pNativeNDirectTarget;
2046         if (pMD->IsQCall())
2047         {
2048 #ifdef FEATURE_STACK_PROBE
2049             // We need just the stack probe for QCalls
2050             RetailStackProbe(ADJUST_PROBE(DEFAULT_ENTRY_PROBE_AMOUNT));
2051 #endif
2052             PInvokeStubForHostInner(dwStackSize, pStackFrame, pTarget);
2053             return;
2054         }
2055     }
2056 #ifdef FEATURE_COMINTEROP
2057     else if (pMD->IsComPlusCall() || pMD->IsEEImpl())
2058     {
2059         LPVOID *lpVtbl = *(LPVOID **)pThis;
2060         ComPlusCallInfo *pComPlusCallInfo = ComPlusCallInfo::FromMethodDesc(pMD);
2061         pTarget = lpVtbl[pComPlusCallInfo->m_cachedComSlot];
2062     }
2063 #endif // FEATURE_COMINTEROP
2064     else
2065     {
2066         UNREACHABLE_MSG("Unexpected MethodDesc kind encountered in PInvokeStubForHostWorker");
2067     }
2068
2069     // We ask the host on every call. This is different from x86 but we keep this
2070     // behavior for maximum compatibility with previous releases.
2071     if (CallNeedsHostHook((size_t)pTarget))
2072     {
2073         // call LeaveRuntime
2074         class LeaveRuntimeHolderThrowComplus
2075         {
2076         public:
2077             LeaveRuntimeHolderThrowComplus(size_t target)
2078             {
2079                 Thread::LeaveRuntimeThrowComplus(target);
2080             }
2081             ~LeaveRuntimeHolderThrowComplus()
2082             {
2083                 Thread::EnterRuntime();
2084             }
2085         } holder((size_t)pTarget);
2086
2087         PInvokeStubForHostInner(dwStackSize, pStackFrame, pTarget);
2088         // ~LeaveRuntimeHolderThrowComplus calls EnterRuntime here
2089     }
2090     else
2091     {
2092         // The host doesn't want to be notified - just call the target
2093         PInvokeStubForHostInner(dwStackSize, pStackFrame, pTarget);
2094     }
2095 }
2096 #endif // _WIN64 && !FEATURE_PAL
2097
2098
2099
2100 void UnmanagedToManagedFrame::ExceptionUnwind()
2101 {
2102     WRAPPER_NO_CONTRACT;
2103
2104     AppDomain::ExceptionUnwind(this);
2105 }
2106
2107 #endif // !DACCESS_COMPILE
2108
2109 void ContextTransitionFrame::GcScanRoots(promote_func *fn, ScanContext* sc)
2110 {
2111     WRAPPER_NO_CONTRACT;
2112
2113     // Don't check app domains here - m_ReturnExecutionContext is in the parent frame's app domain
2114     (*fn)(dac_cast<PTR_PTR_Object>(PTR_HOST_MEMBER_TADDR(ContextTransitionFrame, this, m_ReturnExecutionContext)), sc, 0);
2115     LOG((LF_GC, INFO3, "    " FMT_ADDR "\n", DBG_ADDR(m_ReturnExecutionContext) ));
2116
2117     // Don't check app domains here - m_LastThrownObjectInParentContext is in the parent frame's app domain
2118     (*fn)(dac_cast<PTR_PTR_Object>(PTR_HOST_MEMBER_TADDR(ContextTransitionFrame, this, m_LastThrownObjectInParentContext)), sc, 0);
2119     LOG((LF_GC, INFO3, "    " FMT_ADDR "\n", DBG_ADDR(m_LastThrownObjectInParentContext) ));
2120     
2121     // don't need to worry about the object moving as it is stored in a weak handle
2122     // but do need to report it so it doesn't get collected if the only reference to
2123     // it is in this frame. So only do something if are in promotion phase. And if are
2124     // in reloc phase this could cause invalid refs as the object may have been moved.
2125     if (! sc->promotion)
2126         return;
2127         
2128     // The dac only cares about strong references at the moment.  Since this is always
2129     // in a weak ref, we don't report it here.
2130 #if defined(FEATURE_REMOTING) && !defined(DACCESS_COMPILE)
2131     Context *returnContext = GetReturnContext();
2132     PREFIX_ASSUME(returnContext != NULL);
2133     _ASSERTE(returnContext);
2134     _ASSERTE(returnContext->GetDomain());    // this will make sure is a valid pointer
2135
2136     // In the VM we operate on a local to avoid double relocation.  In the dac we actually want
2137     // to know the real location.
2138 #ifdef DACCESS_COMPILE
2139     PTR_PTR_Object ppRef = returnContext->GetExposedObjectRawUncheckedPtr();
2140     
2141     if (*ppRef == NULL)
2142         return;
2143         
2144     (*fn)(ppRef, sc, 0);
2145
2146 #else // DACCESS_COMPILE
2147     // We are in the middle of the GC. OBJECTREFs can't be used here since their built-in validation
2148     // chokes on objects that have been relocated already
2149     Object *pRef = returnContext->GetExposedObjectRawUnchecked();
2150     
2151     if (pRef == NULL)
2152         return;
2153
2154     LOG((LF_GC, INFO3, "ContextTransitionFrame Protection Frame Promoting" FMT_ADDR "to ", DBG_ADDR(pRef) ));
2155     // Don't check app domains here - the objects are in the parent frame's app domain
2156
2157     (*fn)(&pRef, sc, 0);
2158     LOG((LF_GC, INFO3, FMT_ADDR "\n", DBG_ADDR(pRef)));    
2159 #endif // !DACCESS_COMPILE
2160
2161 #endif    
2162 }
2163
2164
2165 PCODE UnmanagedToManagedFrame::GetReturnAddress()
2166 {
2167     WRAPPER_NO_CONTRACT;
2168     
2169     PCODE pRetAddr = Frame::GetReturnAddress();
2170
2171     if (InlinedCallFrame::FrameHasActiveCall(m_Next) &&
2172         pRetAddr == m_Next->GetReturnAddress())
2173     {
2174         // there's actually no unmanaged code involved - we were called directly
2175         // from managed code using an InlinedCallFrame
2176         return NULL;
2177     }
2178     else
2179     {
2180         return pRetAddr;
2181     }
2182 }