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